summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp14
-rw-r--r--TEST_MAPPING6
-rw-r--r--apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt75
-rw-r--r--apct-tests/perftests/core/src/android/permission/OWNERS3
-rw-r--r--apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java3
-rw-r--r--api/Android.bp2
-rw-r--r--api/api.go136
-rw-r--r--api/api_test.go115
-rw-r--r--api/coverage/tools/ExtractFlaggedApis.kt2
-rw-r--r--api/coverage/tools/extract_flagged_apis.proto2
-rw-r--r--api/go.mod2
-rw-r--r--api/go.work2
-rw-r--r--config/dirty-image-objects1985
-rw-r--r--core/api/current.txt23
-rw-r--r--core/api/module-lib-current.txt1
-rw-r--r--core/api/system-current.txt17
-rw-r--r--core/api/system-lint-baseline.txt2
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java84
-rw-r--r--core/java/android/app/Activity.java17
-rw-r--r--core/java/android/app/ActivityThread.java2
-rw-r--r--core/java/android/app/AppOpsManager.java28
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/ApplicationStartInfo.java11
-rw-r--r--core/java/android/app/AutomaticZenRule.java32
-rw-r--r--core/java/android/app/FullscreenRequestHandler.java24
-rw-r--r--core/java/android/app/IGameManagerService.aidl2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java2
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java41
-rw-r--r--core/java/android/appwidget/flags.aconfig7
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java5
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java37
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl3
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/LauncherApps.java72
-rw-r--r--core/java/android/content/pm/PackageInfo.java2
-rw-r--r--core/java/android/content/pm/PackageInstaller.java11
-rw-r--r--core/java/android/content/pm/PackageManager.java24
-rw-r--r--core/java/android/content/pm/SharedLibraryInfo.java82
-rw-r--r--core/java/android/content/pm/multiuser.aconfig7
-rw-r--r--core/java/android/hardware/biometrics/AuthenticationStateListener.aidl36
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java38
-rw-r--r--core/java/android/hardware/biometrics/BiometricRequestConstants.java (renamed from core/java/android/hardware/biometrics/BiometricOverlayConstants.java)25
-rw-r--r--core/java/android/hardware/biometrics/IAuthService.aidl7
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java2
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java2
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java4
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java4
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java1
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl9
-rw-r--r--core/java/android/nfc/NfcAdapter.java16
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java20
-rw-r--r--core/java/android/os/BatteryStats.java4
-rw-r--r--core/java/android/os/Binder.java5
-rw-r--r--core/java/android/os/Broadcaster.java1
-rw-r--r--core/java/android/os/BundleMerger.java1
-rw-r--r--core/java/android/os/ConditionVariable.java1
-rw-r--r--core/java/android/os/PackageTagsList.java1
-rw-r--r--core/java/android/os/Parcel.java2
-rw-r--r--core/java/android/os/TimestampedValue.java1
-rw-r--r--core/java/android/os/WorkSource.java7
-rw-r--r--core/java/android/os/flags.aconfig7
-rw-r--r--core/java/android/os/storage/OWNERS2
-rw-r--r--core/java/android/os/vibrator/flags.aconfig7
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/security/NetworkSecurityPolicy.java21
-rw-r--r--core/java/android/security/flags.aconfig7
-rw-r--r--core/java/android/security/net/config/ApplicationConfig.java21
-rw-r--r--core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java2
-rw-r--r--core/java/android/security/net/config/NetworkSecurityConfig.java45
-rw-r--r--core/java/android/security/net/config/XmlConfigSource.java15
-rw-r--r--core/java/android/service/notification/Condition.java24
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java1
-rw-r--r--core/java/android/service/persistentdata/OWNERS1
-rw-r--r--core/java/android/service/voice/HotwordRejectedResult.java20
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java6
-rw-r--r--core/java/android/service/voice/flags/flags.aconfig7
-rw-r--r--core/java/android/view/ISurfaceControlViewHostParent.aidl3
-rw-r--r--core/java/android/view/IWindowSession.aidl6
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java1
-rw-r--r--core/java/android/view/SurfaceView.java38
-rw-r--r--core/java/android/view/View.java5
-rw-r--r--core/java/android/view/ViewRootImpl.java121
-rw-r--r--core/java/android/view/ViewTreeObserver.java19
-rw-r--r--core/java/android/view/WindowManager.java10
-rw-r--r--core/java/android/view/WindowlessWindowManager.java19
-rw-r--r--core/java/android/view/accessibility/flags/accessibility_flags.aconfig7
-rw-r--r--core/java/android/view/autofill/AutofillManager.java7
-rw-r--r--core/java/android/view/contentprotection/flags/content_protection_flags.aconfig7
-rw-r--r--core/java/android/view/flags/refresh_rate_flags.aconfig8
-rw-r--r--core/java/android/widget/RemoteViews.java19
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig2
-rw-r--r--core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java5
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl2
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java11
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java18
-rw-r--r--core/java/com/android/internal/jank/Cuj.java9
-rw-r--r--core/java/com/android/internal/net/TEST_MAPPING2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistory.java13
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistoryIterator.java1
-rw-r--r--core/java/com/android/internal/os/BinderCallHeavyHitterWatcher.java1
-rw-r--r--core/java/com/android/internal/os/BinderDeathDispatcher.java1
-rw-r--r--core/java/com/android/internal/os/BinderLatencyBuckets.java1
-rw-r--r--core/java/com/android/internal/os/BinderfsStatsReader.java1
-rw-r--r--core/java/com/android/internal/os/CachedDeviceState.java1
-rw-r--r--core/java/com/android/internal/os/Clock.java1
-rw-r--r--core/java/com/android/internal/os/CpuScalingPolicies.java1
-rw-r--r--core/java/com/android/internal/os/CpuScalingPolicyReader.java1
-rw-r--r--core/java/com/android/internal/os/KernelCpuThreadReader.java3
-rw-r--r--core/java/com/android/internal/os/LoggingPrintStream.java1
-rw-r--r--core/java/com/android/internal/os/LooperStats.java1
-rw-r--r--core/java/com/android/internal/os/MonotonicClock.java1
-rw-r--r--core/java/com/android/internal/os/PowerStats.java2
-rw-r--r--core/java/com/android/internal/os/ProcLocksReader.java1
-rw-r--r--core/java/com/android/internal/os/ProcStatsUtil.java17
-rw-r--r--core/java/com/android/internal/os/StoragedUidIoStatsReader.java16
-rw-r--r--core/java/com/android/internal/pm/parsing/AppInfoUtils.java124
-rw-r--r--core/java/com/android/internal/pm/parsing/PackageParserException.java30
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java128
-rw-r--r--core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java (renamed from services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java)76
-rw-r--r--core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java (renamed from services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java)10
-rw-r--r--core/java/com/android/internal/pm/pkg/SEInfoUtil.java30
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java)10
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java)23
-rw-r--r--core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java (renamed from services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java)17
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java)13
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java)9
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java)4
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java)3
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java)16
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java)13
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java)5
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java)9
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java)13
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java)14
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java)8
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java)5
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java)7
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java)9
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java)14
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java)7
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java (renamed from services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java)11
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java (renamed from services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java)98
-rw-r--r--core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java (renamed from services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java)9
-rw-r--r--core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java (renamed from services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java)6
-rw-r--r--core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java (renamed from services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java)6
-rw-r--r--core/java/com/android/internal/pm/split/SplitAssetLoader.java (renamed from services/core/java/com/android/server/pm/split/SplitAssetLoader.java)2
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java15
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java15
-rw-r--r--core/java/com/android/internal/widget/LockscreenCredential.java10
-rw-r--r--core/java/com/android/server/pm/pkg/AndroidPackage.java7
-rw-r--r--core/jni/android_util_Process.cpp40
-rw-r--r--core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp14
-rw-r--r--core/proto/android/providers/settings/secure.proto1
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values/attrs.xml11
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/public-staging.xml2
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/Android.bp46
-rw-r--r--core/tests/coretests/src/android/app/AutomaticZenRuleTest.java74
-rw-r--r--core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java7
-rw-r--r--core/tests/coretests/src/android/os/AidlTest.java54
-rw-r--r--core/tests/coretests/src/android/os/BinderDeathRecipientTest.java7
-rw-r--r--core/tests/coretests/src/android/os/BinderProxyCountingTest.java13
-rw-r--r--core/tests/coretests/src/android/os/BinderProxyTest.java31
-rw-r--r--core/tests/coretests/src/android/os/BinderTest.java25
-rw-r--r--core/tests/coretests/src/android/os/BinderThreadPriorityTest.java45
-rw-r--r--core/tests/coretests/src/android/os/BinderWorkSourceTest.java14
-rw-r--r--core/tests/coretests/src/android/os/BroadcasterTest.java19
-rw-r--r--core/tests/coretests/src/android/os/BundleTest.java12
-rw-r--r--core/tests/coretests/src/android/os/CancellationSignalBeamerTest.java44
-rw-r--r--core/tests/coretests/src/android/os/EnvironmentTest.java7
-rw-r--r--core/tests/coretests/src/android/os/FileBridgeTest.java42
-rw-r--r--core/tests/coretests/src/android/os/FileObserverTest.java29
-rw-r--r--core/tests/coretests/src/android/os/HandlerThreadTest.java23
-rw-r--r--core/tests/coretests/src/android/os/IdleHandlerTest.java15
-rw-r--r--core/tests/coretests/src/android/os/IpcDataCacheTest.java9
-rw-r--r--core/tests/coretests/src/android/os/LocaleListTest.java23
-rw-r--r--core/tests/coretests/src/android/os/MemoryFileTest.java32
-rw-r--r--core/tests/coretests/src/android/os/MessageQueueTest.java19
-rw-r--r--core/tests/coretests/src/android/os/MessengerTest.java37
-rw-r--r--core/tests/coretests/src/android/os/OsTests.java35
-rw-r--r--core/tests/coretests/src/android/os/ParcelNullabilityTest.java9
-rw-r--r--core/tests/coretests/src/android/os/ParcelTest.java12
-rw-r--r--core/tests/coretests/src/android/os/PatternMatcherTest.java7
-rw-r--r--core/tests/coretests/src/android/os/PerformanceCollectorTest.java52
-rw-r--r--core/tests/coretests/src/android/os/PerformanceHintManagerTest.java7
-rw-r--r--core/tests/coretests/src/android/os/PowerManagerTest.java32
-rw-r--r--core/tests/coretests/src/android/os/ProcessTest.java20
-rw-r--r--core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java7
-rw-r--r--core/tests/coretests/src/android/os/TraceTest.java22
-rw-r--r--core/tests/coretests/src/android/os/VintfObjectTest.java19
-rw-r--r--core/tests/coretests/src/android/os/WorkSourceParcelTest.java17
-rw-r--r--core/tests/coretests/src/android/os/WorkSourceTest.java37
-rw-r--r--core/tests/coretests/src/android/service/notification/ConditionTest.java59
-rw-r--r--core/tests/coretests/src/android/util/SparseSetArrayTest.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java46
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java15
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderHeavyHitterTest.java15
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderfsStatsReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/CpuScalingPolicyReaderTest.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/DebugTest.java15
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java8
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java18
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java29
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java16
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java5
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MonotonicClockTest.java8
-rw-r--r--core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java13
-rw-r--r--core/tests/coretests/src/com/android/internal/os/ProcessCpuTrackerTest.java8
-rw-r--r--core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java14
-rw-r--r--core/tests/coretests/src/com/android/internal/power/EnergyConsumerStatsTest.java6
-rw-r--r--core/tests/utiltests/src/android/util/TimeUtilsTest.java10
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java12
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java2
-rw-r--r--libs/WindowManager/Shell/OWNERS2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java75
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java31
-rw-r--r--libs/WindowManager/Shell/tests/OWNERS3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java38
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java36
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java52
-rw-r--r--libs/hwui/Android.bp8
-rw-r--r--libs/input/tests/Android.bp3
-rw-r--r--libs/input/tests/PointerController_test.cpp37
-rw-r--r--media/OWNERS1
-rw-r--r--media/java/android/media/OWNERS1
-rw-r--r--media/java/android/media/tv/ITvInputManager.aidl4
-rw-r--r--media/java/android/media/tv/ITvInputSession.aidl3
-rw-r--r--media/java/android/media/tv/ITvInputSessionWrapper.java21
-rw-r--r--media/java/android/media/tv/TvInputManager.java32
-rw-r--r--media/java/android/media/tv/TvInputService.java41
-rw-r--r--media/java/android/media/tv/TvView.java30
-rw-r--r--media/java/android/media/tv/ad/TvAdService.java8
-rw-r--r--packages/CompanionDeviceManager/res/values/strings.xml23
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java50
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java159
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java86
-rw-r--r--packages/PackageInstaller/res/values/strings.xml5
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java17
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java51
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt37
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt1
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt9
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt58
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt2
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt31
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt26
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt6
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java29
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java39
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java73
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java52
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java464
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java231
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig7
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt14
-rw-r--r--packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt1
-rw-r--r--packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt38
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt45
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt246
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt75
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt15
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt95
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt95
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt26
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt51
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt18
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt24
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt213
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt66
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt83
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt109
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt109
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt19
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt10
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt96
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt15
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt106
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt20
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt44
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt66
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt171
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java42
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt80
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt20
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt30
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt40
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt95
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt86
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt52
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt176
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt91
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt72
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt89
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt98
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt21
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt172
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java1
-rw-r--r--packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml24
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml3
-rw-r--r--packages/SystemUI/res/drawable/arrow_pointing_down.xml26
-rw-r--r--packages/SystemUI/res/layout/record_issue_dialog.xml81
-rw-r--r--packages/SystemUI/res/layout/sidefps_view.xml2
-rw-r--r--packages/SystemUI/res/values-night/colors.xml3
-rw-r--r--packages/SystemUI/res/values/colors.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml20
-rw-r--r--packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java56
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt124
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt (renamed from packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt112
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt224
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt229
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/ObservableCommunalTransitionState.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt195
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt103
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/OWNERS10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt113
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/Log.kt40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt176
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt173
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt484
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt84
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt576
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt238
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt410
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt94
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java193
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java122
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java11
-rw-r--r--packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt35
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt34
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt30
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt29
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt38
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.kt26
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt35
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt52
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt4
-rw-r--r--packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java260
-rw-r--r--ravenwood/api-maintainers.md21
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java79
-rw-r--r--ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java6
-rw-r--r--ravenwood/ravenwood-annotation-allowed-classes.txt37
-rw-r--r--ravenwood/test-authors.md38
-rw-r--r--services/accessibility/Android.bp3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java18
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java64
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java1
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java6
-rw-r--r--services/autofill/bugfixes.aconfig7
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java5
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java6
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java4
-rw-r--r--services/core/Android.bp4
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java31
-rw-r--r--services/core/java/com/android/server/BatteryService.java15
-rw-r--r--services/core/java/com/android/server/TEST_MAPPING6
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java23
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java87
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/am/AppStartInfoTracker.java122
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java26
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java7
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java7
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java2
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java30
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java123
-rw-r--r--services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java67
-rw-r--r--services/core/java/com/android/server/app/flags.aconfig9
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java3
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java2
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java3
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java21
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java108
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/EnrollClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java43
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java40
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java39
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java37
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java33
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java38
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java4
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java31
-rw-r--r--services/core/java/com/android/server/devicestate/OverrideRequest.java13
-rw-r--r--services/core/java/com/android/server/devicestate/OverrideRequestController.java15
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java4
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java9
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/display/mode/DisplayModeDirector.java27
-rw-r--r--services/core/java/com/android/server/display/mode/Vote.java4
-rw-r--r--services/core/java/com/android/server/display/mode/VoteSummary.java12
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java7
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java19
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java13
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java55
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java6
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java63
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java4
-rw-r--r--services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java (renamed from services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java)34
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java14
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java13
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java7
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java7
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java14
-rw-r--r--services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java15
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java22
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerInternal.java19
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java89
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java4
-rw-r--r--services/core/java/com/android/server/notification/flags.aconfig14
-rw-r--r--services/core/java/com/android/server/pdb/PersistentDataBlockService.java4
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java13
-rw-r--r--services/core/java/com/android/server/pm/Computer.java13
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java38
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageAction.java4
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java65
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java18
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java4
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java25
-rw-r--r--services/core/java/com/android/server/pm/InstallRequest.java5
-rw-r--r--services/core/java/com/android/server/pm/KnownPackages.java4
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java53
-rw-r--r--services/core/java/com/android/server/pm/PackageArchiver.java61
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java26
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java73
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageRemovedInfo.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java5
-rw-r--r--services/core/java/com/android/server/pm/ReconcilePackageUtils.java35
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java216
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java4
-rw-r--r--services/core/java/com/android/server/pm/ScanRequest.java2
-rw-r--r--services/core/java/com/android/server/pm/Settings.java40
-rw-r--r--services/core/java/com/android/server/pm/SharedLibrariesImpl.java2
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java171
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java10
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java1
-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.java69
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageParser2.java20
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java65
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java23
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/SELinuxUtil.java6
-rw-r--r--services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java5
-rw-r--r--services/core/java/com/android/server/pm/resolution/ComponentResolver.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java131
-rw-r--r--services/core/java/com/android/server/policy/TalkbackShortcutController.java118
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsCollector.java28
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsScheduler.java39
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java14
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java40
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorControlService.java105
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorControllerHolder.java70
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java9
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java9
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java142
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java28
-rw-r--r--services/core/java/com/android/server/wm/ClientLifecycleManager.java107
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java9
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java20
-rw-r--r--services/core/java/com/android/server/wm/DragState.java7
-rw-r--r--services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java18
-rw-r--r--services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java20
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java3
-rw-r--r--services/core/java/com/android/server/wm/Session.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java43
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java4
-rw-r--r--services/core/jni/com_android_server_app_GameManagerService.cpp18
-rw-r--r--services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java4
-rw-r--r--services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig8
-rw-r--r--services/manifest_services.xml5
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt2
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt34
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionService.kt20
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java2
-rw-r--r--services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt6
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java16
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java142
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java34
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java17
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java8
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt3
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java81
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt44
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt22
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt14
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt10
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt12
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt6
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt7
-rw-r--r--services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt2
-rw-r--r--services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt2
-rw-r--r--services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt2
-rw-r--r--services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt2
-rw-r--r--services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BasePermissionPolicyTest.kt (renamed from services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt)2
-rw-r--r--services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/DevicePermissionPolicyTest.kt282
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt100
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java175
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java22
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt114
-rw-r--r--services/tests/powerstatstests/Android.bp23
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java (renamed from services/tests/powerstatstests/src/com/android/server/power/stats/AggregatePowerStatsProcessorTest.java)2
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java12
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java62
-rw-r--r--services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java5
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java273
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java13
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java63
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java72
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java7
-rw-r--r--services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java58
-rw-r--r--services/tests/voiceinteractiontests/Android.bp1
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java180
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java43
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java117
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java4
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java9
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java12
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java5
-rw-r--r--telephony/java/android/telephony/CarrierRestrictionRules.java24
-rw-r--r--telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java5
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java10
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java58
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java2
-rw-r--r--telephony/java/android/telephony/satellite/NtnSignalStrength.java3
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java21
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl48
-rw-r--r--tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt3
-rw-r--r--tools/aapt2/integration-tests/SymlinkTest/Android.bp3
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java9
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java22
865 files changed, 20742 insertions, 5502 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index b8538fb567d5..705a4df6c30f 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -26,6 +26,7 @@ aconfig_srcjars = [
":android.os.flags-aconfig-java{.generated_srcjars}",
":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
":android.security.flags-aconfig-java{.generated_srcjars}",
+ ":android.server.app.flags-aconfig-java{.generated_srcjars}",
":android.service.chooser.flags-aconfig-java{.generated_srcjars}",
":android.service.dreams.flags-aconfig-java{.generated_srcjars}",
":android.service.notification.flags-aconfig-java{.generated_srcjars}",
@@ -853,6 +854,19 @@ java_aconfig_library {
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// App
+aconfig_declarations {
+ name: "android.server.app.flags-aconfig",
+ package: "android.server.app",
+ srcs: ["services/core/java/com/android/server/app/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.server.app.flags-aconfig-java",
+ aconfig_declarations: "android.server.app.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// WebView
aconfig_declarations {
name: "android.webkit.flags-aconfig",
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 3409838b5611..117faa203325 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -126,6 +126,12 @@
"exclude-annotation": "org.junit.Ignore"
}
]
+ },
+ {
+ "name": "vts_treble_vintf_framework_test"
+ },
+ {
+ "name": "vts_treble_vintf_vendor_test"
}
],
"postsubmit-ravenwood": [
diff --git a/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt b/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
new file mode 100644
index 000000000000..2af878e60db7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
@@ -0,0 +1,75 @@
+/*
+ * 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.permission
+
+import android.app.AppOpsManager
+import android.content.Context
+import androidx.benchmark.BenchmarkState
+import androidx.benchmark.junit4.BenchmarkRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+@LargeTest
+/**
+ * Performance unit tests for app ops APIs.
+ *
+ * The APIs under test are used for checking permissions and tracking permission accesses and are
+ * therefore invoked frequently by the system for all permission-protected data accesses, hence
+ * these APIs should be monitored closely for performance.
+ */
+class AppOpsPerfTest {
+ @get:Rule val mBenchmarkRule: BenchmarkRule = BenchmarkRule()
+ private lateinit var appOpsManager: AppOpsManager
+ private lateinit var opPackageName: String
+ private var opPackageUid: Int = 0
+
+ @Before
+ fun setUp() {
+ val context: Context = ApplicationProvider.getApplicationContext()
+ appOpsManager = context.getSystemService<AppOpsManager>(AppOpsManager::class.java)!!
+ opPackageName = context.getOpPackageName()
+ opPackageUid = context.getPackageManager().getPackageUid(opPackageName, 0)
+ }
+
+ @Test
+ fun testNoteOp() {
+ val state: BenchmarkState = mBenchmarkRule.getState()
+ while (state.keepRunning()) {
+ appOpsManager.noteOp(
+ AppOpsManager.OPSTR_FINE_LOCATION,
+ opPackageUid,
+ opPackageName,
+ null,
+ null
+ )
+ }
+ }
+
+ @Test
+ fun testUnsafeCheckOp() {
+ val state: BenchmarkState = mBenchmarkRule.getState()
+ while (state.keepRunning()) {
+ appOpsManager.unsafeCheckOp(
+ AppOpsManager.OPSTR_FINE_LOCATION,
+ opPackageUid,
+ opPackageName
+ )
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/permission/OWNERS b/apct-tests/perftests/core/src/android/permission/OWNERS
new file mode 100644
index 000000000000..b4b2b9e30e90
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/permission/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 137825
+
+include platform/frameworks/base:/core/java/android/permission/OWNERS \ No newline at end of file
diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
index 6d1e6d0cbd73..4352c8ae982e 100644
--- a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
@@ -24,10 +24,11 @@ import android.content.pm.parsing.result.ParseTypeImpl
import android.content.res.TypedArray
import android.perftests.utils.BenchmarkState
import android.perftests.utils.PerfStatusReporter
+import android.util.ArraySet
import androidx.test.filters.LargeTest
+import com.android.internal.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.internal.util.ConcurrentUtils
-import com.android.server.pm.parsing.pkg.PackageImpl
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.ArrayBlockingQueue
@@ -214,7 +215,10 @@ public class PackageParsingPerfTest {
path,
manifestArray,
isCoreApp,
+ this,
)
+ override fun getHiddenApiWhitelistedApps() = ArraySet<String>()
+ override fun getInstallConstraintsAllowlist() = ArraySet<String>()
})
override fun parseImpl(file: File) =
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index 03891bbec56a..e3ba50dc635b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -26,6 +26,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -319,8 +320,8 @@ public final class BackgroundJobsController extends StateController {
final boolean isStopped = mPackageManagerInternal.isPackageStopped(packageName, uid);
mPackageStoppedState.add(uid, packageName, isStopped);
return isStopped;
- } catch (IllegalArgumentException e) {
- Slog.d(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
return false;
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 12f455ad0144..bd5c00600044 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2258,7 +2258,8 @@ public class AppStandbyController
}
synchronized (mSystemExemptionAppOpMode) {
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- mSystemExemptionAppOpMode.delete(UserHandle.getUid(userId, getAppId(pkgName)));
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
+ mSystemExemptionAppOpMode.delete(uid);
}
}
diff --git a/api/Android.bp b/api/Android.bp
index 2b1cfcb82d04..9029d252b470 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -31,12 +31,10 @@ bootstrap_go_package {
"blueprint",
"soong",
"soong-android",
- "soong-bp2build",
"soong-genrule",
"soong-java",
],
srcs: ["api.go"],
- testSrcs: ["api_test.go"],
pluginFor: ["soong_build"],
}
diff --git a/api/api.go b/api/api.go
index 71b1e10d2f47..2668999c572e 100644
--- a/api/api.go
+++ b/api/api.go
@@ -22,7 +22,6 @@ import (
"github.com/google/blueprint/proptools"
"android/soong/android"
- "android/soong/bazel"
"android/soong/genrule"
"android/soong/java"
)
@@ -65,7 +64,6 @@ type CombinedApisProperties struct {
type CombinedApis struct {
android.ModuleBase
- android.BazelModuleBase
properties CombinedApisProperties
}
@@ -115,20 +113,6 @@ type defaultsProps struct {
Previous_api *string
}
-type Bazel_module struct {
- Label *string
- Bp2build_available *bool
-}
-type bazelProperties struct {
- *Bazel_module
-}
-
-var bp2buildNotAvailable = bazelProperties{
- &Bazel_module{
- Bp2build_available: proptools.BoolPtr(false),
- },
-}
-
// Struct to pass parameters for the various merged [current|removed].txt file modules we create.
type MergedTxtDefinition struct {
// "current.txt" or "removed.txt"
@@ -143,8 +127,6 @@ type MergedTxtDefinition struct {
ModuleTag string
// public, system, module-lib or system-server
Scope string
- // True if there is a bp2build definition for this module
- Bp2buildDefined bool
}
func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) {
@@ -178,20 +160,7 @@ func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) {
},
}
props.Visibility = []string{"//visibility:public"}
- bazelProps := bazelProperties{
- &Bazel_module{
- Bp2build_available: proptools.BoolPtr(false),
- },
- }
- if txt.Bp2buildDefined {
- moduleDir := ctx.ModuleDir()
- if moduleDir == android.Bp2BuildTopLevel {
- moduleDir = ""
- }
- label := fmt.Sprintf("//%s:%s", moduleDir, moduleName)
- bazelProps.Label = &label
- }
- ctx.CreateModule(genrule.GenRuleFactory, &props, &bazelProps)
+ ctx.CreateModule(genrule.GenRuleFactory, &props)
}
func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules []string) {
@@ -221,7 +190,7 @@ func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, sys
props := fgProps{}
props.Name = proptools.StringPtr(i.name)
props.Srcs = createSrcs(i.modules, i.tag)
- ctx.CreateModule(android.FileGroupFactory, &props, &bp2buildNotAvailable)
+ ctx.CreateModule(android.FileGroupFactory, &props)
}
}
@@ -315,7 +284,7 @@ func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules []str
props.Name = proptools.StringPtr("all-modules-public-stubs-source")
props.Srcs = createSrcs(modules, "{.public.stubs.source}")
props.Visibility = []string{"//frameworks/base"}
- ctx.CreateModule(android.FileGroupFactory, &props, &bp2buildNotAvailable)
+ ctx.CreateModule(android.FileGroupFactory, &props)
}
func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) {
@@ -323,43 +292,38 @@ func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_
tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
distFilename := []string{"android.txt", "android-removed.txt"}
- bp2BuildDefined := []bool{true, false}
for i, f := range []string{"current.txt", "removed.txt"} {
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-" + f,
- Modules: bootclasspath,
- ModuleTag: "{.public" + tagSuffix[i],
- Scope: "public",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-" + f,
+ Modules: bootclasspath,
+ ModuleTag: "{.public" + tagSuffix[i],
+ Scope: "public",
})
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-system-" + f,
- Modules: bootclasspath,
- ModuleTag: "{.system" + tagSuffix[i],
- Scope: "system",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-system-" + f,
+ Modules: bootclasspath,
+ ModuleTag: "{.system" + tagSuffix[i],
+ Scope: "system",
})
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-module-lib-" + f,
- Modules: bootclasspath,
- ModuleTag: "{.module-lib" + tagSuffix[i],
- Scope: "module-lib",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-module-lib-" + f,
+ Modules: bootclasspath,
+ ModuleTag: "{.module-lib" + tagSuffix[i],
+ Scope: "module-lib",
})
textFiles = append(textFiles, MergedTxtDefinition{
- TxtFilename: f,
- DistFilename: distFilename[i],
- BaseTxt: ":non-updatable-system-server-" + f,
- Modules: system_server_classpath,
- ModuleTag: "{.system-server" + tagSuffix[i],
- Scope: "system-server",
- Bp2buildDefined: bp2BuildDefined[i],
+ TxtFilename: f,
+ DistFilename: distFilename[i],
+ BaseTxt: ":non-updatable-system-server-" + f,
+ Modules: system_server_classpath,
+ ModuleTag: "{.system-server" + tagSuffix[i],
+ Scope: "system-server",
})
}
for _, txt := range textFiles {
@@ -446,55 +410,9 @@ func combinedApisModuleFactory() android.Module {
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) })
- android.InitBazelModule(module)
return module
}
-type bazelCombinedApisAttributes struct {
- Scope bazel.StringAttribute
- Base bazel.LabelAttribute
- Deps bazel.LabelListAttribute
-}
-
-// combined_apis bp2build converter
-func (a *CombinedApis) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
- basePrefix := "non-updatable"
- scopeToSuffix := map[string]string{
- "public": "-current.txt",
- "system": "-system-current.txt",
- "module-lib": "-module-lib-current.txt",
- "system-server": "-system-server-current.txt",
- }
-
- for scopeName, suffix := range scopeToSuffix {
- name := a.Name() + suffix
-
- var scope bazel.StringAttribute
- scope.SetValue(scopeName)
-
- var base bazel.LabelAttribute
- base.SetValue(android.BazelLabelForModuleDepSingle(ctx, basePrefix+suffix))
-
- var deps bazel.LabelListAttribute
- classpath := a.properties.Bootclasspath
- if scopeName == "system-server" {
- classpath = a.properties.System_server_classpath
- }
- deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, classpath))
-
- attrs := bazelCombinedApisAttributes{
- Scope: scope,
- Base: base,
- Deps: deps,
- }
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "merged_txts",
- Bzl_load_location: "//build/bazel/rules/java:merged_txts.bzl",
- }
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, &attrs)
- }
-}
-
// Various utility methods below.
// Creates an array of ":<m><tag>" for each m in <modules>.
diff --git a/api/api_test.go b/api/api_test.go
deleted file mode 100644
index 70f2162348ad..000000000000
--- a/api/api_test.go
+++ /dev/null
@@ -1,115 +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 api
-
-import (
- "testing"
-
- "android/soong/android"
- "android/soong/bp2build"
- "android/soong/java"
-)
-
-func runCombinedApisTestCaseWithRegistrationCtxFunc(t *testing.T, tc bp2build.Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
- t.Helper()
- (&tc).ModuleTypeUnderTest = "combined_apis"
- (&tc).ModuleTypeUnderTestFactory = combinedApisModuleFactory
- bp2build.RunBp2BuildTestCase(t, registrationCtxFunc, tc)
-}
-
-func runCombinedApisTestCase(t *testing.T, tc bp2build.Bp2buildTestCase) {
- t.Helper()
- runCombinedApisTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("java_defaults", java.DefaultsFactory)
- ctx.RegisterModuleType("java_sdk_library", java.SdkLibraryFactory)
- ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
- })
-}
-
-func TestCombinedApisGeneral(t *testing.T) {
- runCombinedApisTestCase(t, bp2build.Bp2buildTestCase{
- Description: "combined_apis, general case",
- Blueprint: `combined_apis {
- name: "foo",
- bootclasspath: ["bcp"],
- system_server_classpath: ["ssc"],
-}
-
-java_sdk_library {
- name: "bcp",
- srcs: ["a.java", "b.java"],
- shared_library: false,
-}
-java_sdk_library {
- name: "ssc",
- srcs: ["a.java", "b.java"],
- shared_library: false,
-}
-filegroup {
- name: "non-updatable-current.txt",
- srcs: ["current.txt"],
-}
-filegroup {
- name: "non-updatable-system-current.txt",
- srcs: ["system-current.txt"],
-}
-filegroup {
- name: "non-updatable-module-lib-current.txt",
- srcs: ["system-removed.txt"],
-}
-filegroup {
- name: "non-updatable-system-server-current.txt",
- srcs: ["system-lint-baseline.txt"],
-}
-`,
- Filesystem: map[string]string{
- "a/Android.bp": `
- java_defaults {
- name: "android.jar_defaults",
- }
- `,
- "api/current.txt": "",
- "api/removed.txt": "",
- "api/system-current.txt": "",
- "api/system-removed.txt": "",
- "api/test-current.txt": "",
- "api/test-removed.txt": "",
- },
- StubbedBuildDefinitions: []string{"bcp", "ssc", "non-updatable-current.txt", "non-updatable-system-current.txt", "non-updatable-module-lib-current.txt", "non-updatable-system-server-current.txt"},
- ExpectedHandcraftedModules: []string{"foo-current.txt", "foo-system-current.txt", "foo-module-lib-current.txt", "foo-system-server-current.txt"},
- ExpectedBazelTargets: []string{
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-current.txt", bp2build.AttrNameToString{
- "scope": `"public"`,
- "base": `":non-updatable-current.txt"`,
- "deps": `[":bcp"]`,
- }),
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-current.txt", bp2build.AttrNameToString{
- "scope": `"system"`,
- "base": `":non-updatable-system-current.txt"`,
- "deps": `[":bcp"]`,
- }),
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-module-lib-current.txt", bp2build.AttrNameToString{
- "scope": `"module-lib"`,
- "base": `":non-updatable-module-lib-current.txt"`,
- "deps": `[":bcp"]`,
- }),
- bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-server-current.txt", bp2build.AttrNameToString{
- "scope": `"system-server"`,
- "base": `":non-updatable-system-server-current.txt"`,
- "deps": `[":ssc"]`,
- }),
- },
- })
-}
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index 43caaecebdaf..caa1929abd54 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -43,7 +43,7 @@ fun main(args: Array<String>) {
.setClassName(it.fullName())
.setMethodName(method.name())
for (param in method.parameters()) {
- api.addParameterTypes(param.type().toTypeString())
+ api.addParameters(param.type().toTypeString())
}
if (builder.containsFlagToApi(flagValue)) {
var updatedApis =
diff --git a/api/coverage/tools/extract_flagged_apis.proto b/api/coverage/tools/extract_flagged_apis.proto
index 031d621b178f..4db2a8b03de5 100644
--- a/api/coverage/tools/extract_flagged_apis.proto
+++ b/api/coverage/tools/extract_flagged_apis.proto
@@ -32,6 +32,6 @@ message JavaMethod {
string package_name = 1;
string class_name = 2;
string method_name = 3;
- repeated string parameter_types = 4;
+ repeated string parameters = 4;
}
diff --git a/api/go.mod b/api/go.mod
index f8bb1c01cd96..445a6f4a5ec6 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -6,7 +6,5 @@ require (
android/soong v0.0.0
github.com/google/blueprint v0.0.0
google.golang.org/protobuf v0.0.0
- prebuilts/bazel/common/proto/analysis_v2 v0.0.0
- prebuilts/bazel/common/proto/build v0.0.0
go.starlark.net v0.0.0
)
diff --git a/api/go.work b/api/go.work
index aa2d2b1cb461..edd002e7efba 100644
--- a/api/go.work
+++ b/api/go.work
@@ -13,7 +13,5 @@ replace (
google.golang.org/protobuf v0.0.0 => ../../../external/golang-protobuf
github.com/google/blueprint v0.0.0 => ../../../build/blueprint
github.com/google/go-cmp v0.0.0 => ../../../external/go-cmp
- prebuilts/bazel/common/proto/analysis_v2 v0.0.0 => ../../../prebuilts/bazel/common/proto/analysis_v2
- prebuilts/bazel/common/proto/build v0.0.0 => ../../../prebuilts/bazel/common/proto/build
go.starlark.net v0.0.0 => ../../../external/starlark-go
)
diff --git a/config/dirty-image-objects b/config/dirty-image-objects
index 2584610e2848..f2e2b82cd82a 100644
--- a/config/dirty-image-objects
+++ b/config/dirty-image-objects
@@ -16,282 +16,1713 @@
#
#
# Dirty-image-objects file for boot image.
-#
-# Objects in this file are known dirty at runtime. Current this includes:
-# - classes with known dirty static fields.
-#
# The image writer will bin these objects together in the image.
+# More info about dirty objects format and how to collect the data can be
+# found in: art/imgdiag/dirty_image_objects.md
+# This particular file was generated by dumping all pre-installed apps.
#
-# This file can be generated using imgdiag with a command such as:
-# adb shell imgdiag --image-diff-pid=<app pid> --zygote-diff-pid=<zygote pid> \
-# --boot-image=/system/framework/boot.art --dump-dirty-objects
-# Then, grep for lines containing "Private dirty object" from the output.
-# This particular file was generated by dumping systemserver and systemui.
-#
-Landroid/animation/LayoutTransition;
-Landroid/app/ActivityManager;
-Landroid/app/ActivityTaskManager;
-Landroid/app/ActivityThread;
-Landroid/app/AlarmManager;
-Landroid/app/AppOpsManager;
-Landroid/app/ContextImpl;
-Landroid/app/Notification;
-Landroid/app/NotificationManager;
-Landroid/app/PendingIntent$FinishedDispatcher;
-Landroid/app/PropertyInvalidatedCache$NoPreloadHolder;
-Landroid/app/QueuedWork;
-Landroid/app/ResourcesManager;
-Landroid/app/SystemServiceRegistry;
-Landroid/app/WallpaperManager;
-Landroid/app/backup/BackupManager;
-Landroid/compat/Compatibility;
-Landroid/content/AsyncQueryHandler;
-Landroid/content/ContentProviderClient;
-Landroid/content/ContentResolver;
-Landroid/content/Context;
-Landroid/content/pm/PackageItemInfo;
-Landroid/content/pm/UserPackage;
-Landroid/content/res/ResourceTimer;
-Landroid/database/CursorWindow;
-Landroid/database/sqlite/SQLiteCompatibilityWalFlags;
-Landroid/database/sqlite/SQLiteDebug$NoPreloadHolder;
-Landroid/database/sqlite/SQLiteGlobal;
-Landroid/ddm/DdmHandleAppName;
-Landroid/graphics/Bitmap;
-Landroid/graphics/Canvas;
-Landroid/graphics/Compatibility;
-Landroid/graphics/HardwareRenderer;
-Landroid/graphics/TemporaryBuffer;
-Landroid/graphics/Typeface;
-Landroid/graphics/drawable/AdaptiveIconDrawable;
-Landroid/hardware/SensorPrivacyManager;
-Landroid/hardware/SystemSensorManager;
-Landroid/hardware/devicestate/DeviceStateManagerGlobal;
-Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal;
-Landroid/hardware/display/DisplayManagerGlobal;
-Landroid/hardware/input/InputManagerGlobal;
-Landroid/hardware/location/GeofenceHardwareImpl;
-Landroid/icu/impl/number/range/StandardPluralRanges;
-Landroid/icu/text/Collator;
-Landroid/icu/util/TimeZone;
-Landroid/location/LocationManager;
-Landroid/media/AudioManager;
-Landroid/media/AudioPlaybackConfiguration;
-Landroid/media/AudioSystem;
-Landroid/media/MediaCodec;
-Landroid/media/MediaCodecList;
-Landroid/media/MediaFrameworkPlatformInitializer;
-Landroid/media/MediaRouter2Manager;
-Landroid/media/MediaRouter;
-Landroid/media/PlayerBase;
-Landroid/media/audiopolicy/AudioProductStrategy;
-Landroid/media/audiopolicy/AudioVolumeGroup;
-Landroid/nfc/NfcAdapter;
-Landroid/nfc/NfcFrameworkInitializer;
-Landroid/nfc/cardemulation/CardEmulation;
-Landroid/os/AsyncTask;
-Landroid/os/BaseBundle;
-Landroid/os/Binder;
-Landroid/os/BinderProxy;
-Landroid/os/Environment;
-Landroid/os/FileObserver;
-Landroid/os/Handler;
-Landroid/os/LocaleList;
-Landroid/os/Looper;
-Landroid/os/Message;
-Landroid/os/NullVibrator;
-Landroid/os/Parcel;
-Landroid/os/Process;
-Landroid/os/ServiceManager;
-Landroid/os/StrictMode;
-Landroid/os/UEventObserver;
-Landroid/os/UserManager;
-Landroid/os/WorkSource;
-Landroid/os/storage/StorageManager;
-Landroid/permission/PermissionManager;
-Landroid/provider/DeviceConfigInitializer;
-Landroid/provider/FontsContract;
-Landroid/provider/Settings;
-Landroid/renderscript/RenderScript;
-Landroid/renderscript/RenderScriptCacheDir;
-Landroid/security/keystore2/KeyStoreCryptoOperationUtils;
-Landroid/security/net/config/ApplicationConfig;
-Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder;
-Landroid/security/net/config/UserCertificateSource$NoPreloadHolder;
-Landroid/telecom/Log;
-Landroid/telecom/TelecomManager;
-Landroid/telephony/AnomalyReporter;
-Landroid/telephony/TelephonyFrameworkInitializer;
-Landroid/telephony/TelephonyLocalConnection;
-Landroid/telephony/TelephonyManager;
-Landroid/telephony/TelephonyRegistryManager;
-Landroid/text/DynamicLayout;
-Landroid/text/TextUtils;
-Landroid/text/format/DateFormat;
-Landroid/text/format/DateUtils;
-Landroid/text/method/ArrowKeyMovementMethod;
-Landroid/text/method/LinkMovementMethod;
-Landroid/text/method/SingleLineTransformationMethod;
-Landroid/text/style/ClickableSpan;
-Landroid/timezone/TelephonyLookup;
-Landroid/timezone/TimeZoneFinder;
-Landroid/util/ArrayMap;
-Landroid/util/ArraySet;
-Landroid/util/EventLog;
-Landroid/util/NtpTrustedTime;
-Landroid/view/Choreographer;
-Landroid/view/CrossWindowBlurListeners;
-Landroid/view/DisplayCutout;
-Landroid/view/KeyEvent;
-Landroid/view/MotionEvent;
-Landroid/view/PointerIcon;
-Landroid/view/RoundedCorners;
-Landroid/view/SurfaceControl;
-Landroid/view/View;
-Landroid/view/ViewGroup$TouchTarget;
-Landroid/view/ViewRootImpl;
-Landroid/view/ViewTreeObserver;
-Landroid/view/WindowManagerGlobal;
-Landroid/view/accessibility/AccessibilityManager;
-Landroid/view/accessibility/AccessibilityNodeIdManager;
-Landroid/view/autofill/Helper;
-Landroid/view/inputmethod/IInputMethodManagerGlobalInvoker;
-Landroid/view/inputmethod/InputMethodManager;
-Landroid/webkit/CookieSyncManager;
-Landroid/webkit/WebView;
-Landroid/webkit/WebViewFactory;
-Landroid/webkit/WebViewZygote;
-Landroid/widget/AbsListView;
-Landroid/widget/ImageView;
-Landroid/widget/LinearLayout;
-Landroid/widget/Toast;
-Landroid/window/SurfaceSyncGroup;
-Lcom/android/i18n/timezone/TelephonyLookup;
-Lcom/android/i18n/timezone/TimeZoneFinder;
-Lcom/android/internal/config/appcloning/AppCloningDeviceConfigHelper;
-Lcom/android/internal/content/om/OverlayConfig;
-Lcom/android/internal/display/BrightnessSynchronizer;
-Lcom/android/internal/infra/AndroidFuture;
-Lcom/android/internal/inputmethod/ImeTracing;
-Lcom/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry;
-Lcom/android/internal/jank/InteractionJankMonitor$InstanceHolder;
-Lcom/android/internal/jank/InteractionJankMonitor;
-Lcom/android/internal/logging/MetricsLogger;
-Lcom/android/internal/os/BackgroundThread;
-Lcom/android/internal/os/BinderInternal;
-Lcom/android/internal/os/KernelCpuBpfTracking;
-Lcom/android/internal/os/RuntimeInit;
-Lcom/android/internal/os/SomeArgs;
-Lcom/android/internal/os/ZygoteInit;
-Lcom/android/internal/policy/AttributeCache;
-Lcom/android/internal/protolog/BaseProtoLogImpl;
-Lcom/android/internal/protolog/ProtoLogImpl;
-Lcom/android/internal/statusbar/NotificationVisibility;
-Lcom/android/internal/telephony/CellBroadcastServiceManager;
-Lcom/android/internal/telephony/IntentBroadcaster;
-Lcom/android/internal/telephony/MccTable;
-Lcom/android/internal/telephony/MultiSimSettingController;
-Lcom/android/internal/telephony/PackageChangeReceiver;
-Lcom/android/internal/telephony/PhoneConfigurationManager;
-Lcom/android/internal/telephony/PhoneFactory;
-Lcom/android/internal/telephony/ProxyController;
-Lcom/android/internal/telephony/RILRequest;
-Lcom/android/internal/telephony/RadioConfig;
-Lcom/android/internal/telephony/RadioInterfaceCapabilityController;
-Lcom/android/internal/telephony/SmsApplication;
-Lcom/android/internal/telephony/SmsBroadcastUndelivered;
-Lcom/android/internal/telephony/SomeArgs;
-Lcom/android/internal/telephony/TelephonyComponentFactory;
-Lcom/android/internal/telephony/TelephonyDevController;
-Lcom/android/internal/telephony/cat/CatService;
-Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler;
-Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
-Lcom/android/internal/telephony/euicc/EuiccCardController;
-Lcom/android/internal/telephony/euicc/EuiccController;
-Lcom/android/internal/telephony/ims/ImsResolver;
-Lcom/android/internal/telephony/metrics/TelephonyMetrics;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$CarrierIdMismatch;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularDataServiceSwitch;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularServiceState;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$DataCallSession;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$EmergencyNumbersInfo;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$GbaEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerListenerEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationFeatureTagStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationServiceDescStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationTermination;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$IncomingSms;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequests;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequestsV2;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingShortCodeSms;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingSms;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$PresenceNotifyEvent;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsAcsProvisioningStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsClientProvisioningStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteController;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteIncomingDatagram;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteOutgoingDatagram;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteProvision;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSession;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSosMessageRecommender;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipDelegateStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipMessageResponse;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportFeatureTagStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportSession;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$UceEventStats;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$UnmeteredNetworks;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallRatUsage;
-Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallSession;
-Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall;
-Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall;
-Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyServiceState$NetworkRegistrationInfo;
-Lcom/android/internal/telephony/satellite/PointingAppController;
-Lcom/android/internal/telephony/satellite/SatelliteModemInterface;
-Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher;
-Lcom/android/internal/util/ContrastColorUtil;
-Lcom/android/internal/view/WindowManagerPolicyThread;
-Lcom/android/org/bouncycastle/crypto/CryptoServicesRegistrar;
-Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo;
-Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo;
-Lcom/android/server/AppWidgetBackupBridge;
-Ldalvik/system/BaseDexClassLoader;
-Ldalvik/system/BlockGuard;
-Ldalvik/system/CloseGuard;
-Ldalvik/system/RuntimeHooks;
-Ldalvik/system/SocketTagger;
-Ldalvik/system/VMRuntime;
-Ldalvik/system/ZipPathValidator;
-Ldalvik/system/ZygoteHooks;
-Ljava/lang/System;
-Ljava/lang/Thread;
-Ljava/lang/Throwable;
-Ljava/lang/ref/FinalizerReference;
-Ljava/lang/ref/ReferenceQueue;
-Ljava/net/ResponseCache;
-Ljava/nio/Bits;
-Ljava/nio/charset/Charset;
-Ljava/security/Provider;
-Ljava/util/Collections;
-Ljava/util/GregorianCalendar;
-Ljava/util/Locale$NoImagePreloadHolder;
-Ljava/util/Locale;
-Ljava/util/Scanner;
-Ljava/util/TimeZone;
-Ljava/util/concurrent/ForkJoinPool;
-Ljava/util/concurrent/ThreadLocalRandom;
-Ljavax/net/ServerSocketFactory;
-Ljavax/net/SocketFactory;
-Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder;
-Ljavax/net/ssl/HttpsURLConnection;
-Ljavax/net/ssl/SSLContext;
-Ljavax/net/ssl/SSLServerSocketFactory;
-Ljavax/net/ssl/SSLSocketFactory;
-Llibcore/io/Libcore;
-Llibcore/net/NetworkSecurityPolicy;
-Lsun/misc/Cleaner;
-Lsun/nio/ch/FileChannelImpl$Unmapper;
-Lsun/nio/ch/FileChannelImpl;
-Lsun/security/jca/Providers;
+Landroid/text/style/URLSpan; 0
+Landroid/content/res/Resources$NotFoundException; 1
+Landroid/os/PowerManager$WakeLock; 2
+Landroid/os/BatterySaverPolicyConfig; 2
+Landroid/content/ContextWrapper; 2
+Landroid/app/WallpaperInfo; 2
+Landroid/content/pm/PackageManager; 2
+Landroid/app/IWallpaperManager; 2
+Ljava/lang/BootClassLoader; 2
+Ljava/time/Duration; 2
+Landroid/util/Printer; 2
+Landroid/app/WallpaperManager$OnColorsChangedListener; 2
+Landroid/app/WallpaperColors; 2
+Landroid/content/pm/ServiceInfo; 2
+Landroid/app/KeyguardManager$KeyguardDismissCallback; 2
+Ljava/lang/CharSequence; 3
+Landroid/widget/Switch; 4
+Lcom/android/internal/util/ContrastColorUtil; 4
+Landroid/view/SurfaceControl; 4
+Landroid/graphics/ColorMatrix;.dexCache:Ljava/lang/Object; 4
+Lcom/android/internal/widget/CachingIconView; 4
+Landroid/window/IRemoteTransition$Stub$Proxy; 4
+Landroid/app/trust/TrustManager$TrustListener; 4
+Landroid/view/NotificationHeaderView; 4
+Lcom/android/internal/widget/ImageResolver; 4
+Landroid/window/WindowContainerTransaction$Change; 4
+Lcom/android/internal/widget/MessagingLayout; 4
+Ljava/util/concurrent/ConcurrentLinkedQueue; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/view/RemotableViewMethod; 4
+Landroid/app/IApplicationThread$Stub$Proxy; 4
+Landroid/os/FileUtils; 4
+Landroid/view/View;.SCALE_X:Landroid/util/Property; 4
+Landroid/widget/GridLayout;.UNDEFINED_ALIGNMENT:Landroid/widget/GridLayout$Alignment; 4
+Landroid/media/MediaPlayer$EventHandler; 4
+Landroid/widget/DateTimeView; 4
+Llibcore/util/ZoneInfo; 4
+Lcom/android/internal/statusbar/IStatusBarService; 4
+Ljava/lang/invoke/MethodType;.internTable:Ljava/lang/invoke/MethodType$ConcurrentWeakInternSet;.stale:Ljava/lang/ref/ReferenceQueue; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/logging/UiEventLogger; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/renderscript/RenderScript; 4
+Landroid/view/ViewTreeObserver$OnWindowVisibilityChangeListener; 4
+Lcom/android/internal/widget/RemeasuringLinearLayout; 4
+Landroid/widget/DateTimeView$ReceiverInfo$1; 4
+Landroid/view/View;.TRANSLATION_Y:Landroid/util/Property; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/widget/NotificationExpandButton; 4
+Lcom/android/internal/view/menu/ActionMenuItemView; 4
+Landroid/view/animation/AnimationSet; 4
+Landroid/hardware/biometrics/BiometricSourceType;.FINGERPRINT:Landroid/hardware/biometrics/BiometricSourceType; 4
+Landroid/window/WindowOrganizer;.IWindowOrganizerControllerSingleton:Landroid/util/Singleton; 4
+Ljava/lang/Runnable; 4
+Lorg/apache/harmony/dalvik/ddmc/DdmServer;.mHandlerMap:Ljava/util/HashMap; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/widget/ImageFloatingTextView; 4
+Landroid/window/IWindowContainerToken$Stub$Proxy; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/content/res/ColorStateList; 4
+Landroid/view/View;.SCALE_Y:Landroid/util/Property; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap; 4
+Lcom/android/internal/widget/ConversationLayout; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry;.right:Ljava/util/TreeMap$TreeMapEntry; 4
+Lcom/android/internal/colorextraction/ColorExtractor$OnColorsChangedListener; 4
+Landroid/hardware/face/FaceManager$FaceDetectionCallback; 4
+Landroid/widget/RemoteViews;.sLookupKey:Landroid/widget/RemoteViews$MethodKey; 4
+Landroid/widget/ViewSwitcher;.dexCache:Ljava/lang/Object; 4
+Lcom/android/internal/widget/NotificationActionListLayout; 4
+Ljava/util/concurrent/ConcurrentLinkedQueue$Node; 4
+Landroid/hardware/biometrics/BiometricSourceType;.FACE:Landroid/hardware/biometrics/BiometricSourceType; 4
+Landroid/hardware/biometrics/BiometricSourceType;.IRIS:Landroid/hardware/biometrics/BiometricSourceType; 4
+Landroid/view/NotificationTopLineView; 4
+Lcom/android/internal/protolog/BaseProtoLogImpl;.LOG_GROUPS:Ljava/util/TreeMap;.root:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry;.left:Ljava/util/TreeMap$TreeMapEntry; 4
+Landroid/widget/RemoteViews;.sMethods:Landroid/util/ArrayMap; 4
+Lcom/android/internal/os/BinderInternal$BinderProxyLimitListener; 5
+Landroid/app/AppOpsManager$OnOpNotedInternalListener; 5
+Lcom/android/internal/R$styleable;.WindowAnimation:[I 5
+Lcom/android/internal/logging/UiEventLogger$UiEventEnum; 5
+Lcom/android/internal/policy/AttributeCache; 5
+Landroid/app/Notification$CallStyle; 5
+Landroid/app/AppOpsManager$OnOpNotedListener; 5
+Lcom/android/internal/protolog/BaseProtoLogImpl; 5
+Landroid/app/AppOpsManager$OnOpStartedListener; 5
+Lcom/android/internal/util/ScreenshotHelper$1; 5
+Landroid/app/Notification$DecoratedCustomViewStyle; 5
+Landroid/view/DisplayCutout; 5
+Landroid/view/InputEvent;.mNextSeq:Ljava/util/concurrent/atomic/AtomicInteger; 5
+Lcom/android/internal/statusbar/NotificationVisibility; 5
+Landroid/telephony/DataSpecificRegistrationInfo; 6
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle; 7
+Landroid/telephony/VoiceSpecificRegistrationInfo; 8
+Landroid/telephony/AnomalyReporter; 8
+Landroid/telephony/TelephonyRegistryManager;.sCarrierPrivilegeCallbacks:Ljava/util/WeakHashMap; 8
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.1:Ljava/util/WeakHashMap$Entry; 8
+Landroid/app/LoadedApk$ServiceDispatcher$InnerConnection; 8
+Landroid/content/ContentProvider$Transport; 8
+Landroid/telephony/NetworkRegistrationInfo; 8
+Landroid/net/MatchAllNetworkSpecifier; 8
+Landroid/telephony/TelephonyRegistryManager;.sCarrierPrivilegeCallbacks:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry; 8
+Landroid/app/PropertyInvalidatedCache;.sInvalidates:Ljava/util/HashMap; 9
+Landroid/app/PropertyInvalidatedCache$NoPreloadHolder; 9
+Landroid/app/PropertyInvalidatedCache;.sDisabledKeys:Ljava/util/HashSet;.map:Ljava/util/HashMap; 10
+Landroid/media/AudioSystem$AudioRecordingCallback; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedString; 11
+Landroid/net/metrics/IpManagerEvent; 11
+Lcom/android/internal/os/ProcessCpuTracker$FilterStats; 11
+Lcom/android/internal/infra/AbstractRemoteService$AsyncRequest; 11
+Landroid/content/pm/RegisteredServicesCache$3; 11
+Lcom/android/internal/os/LooperStats; 11
+Lcom/android/server/AppWidgetBackupBridge; 11
+Landroid/hardware/display/DisplayManagerInternal; 11
+Landroid/content/pm/PackageInfo; 11
+Landroid/hardware/soundtrigger/SoundTriggerModule$EventHandlerDelegate; 11
+Landroid/app/servertransaction/ResumeActivityItem; 11
+Lcom/android/internal/widget/AlertDialogLayout; 11
+Landroid/content/pm/FallbackCategoryProvider;.sFallbacks:Landroid/util/ArrayMap; 11
+Landroid/os/RemoteCallback$1; 11
+Landroid/content/pm/SharedLibraryInfo; 11
+Landroid/util/MemoryIntArray; 11
+Landroid/net/metrics/DhcpErrorEvent; 11
+Lcom/android/internal/util/function/DodecConsumer; 11
+Landroid/provider/Settings; 11
+Landroid/app/PropertyInvalidatedCache;.sCorkLock:Ljava/lang/Object; 11
+Lcom/android/internal/os/CachedDeviceState$Readonly; 11
+Landroid/app/job/JobServiceEngine$JobHandler; 11
+Landroid/app/SystemServiceRegistry; 11
+Lcom/android/internal/os/BinderInternal$CallStatsObserver; 11
+Lcom/android/internal/statusbar/IStatusBar$Stub$Proxy; 11
+Landroid/hardware/location/IActivityRecognitionHardwareClient; 11
+Landroid/telecom/Logging/EventManager$EventListener; 11
+Landroid/accounts/AccountManagerInternal; 11
+Lcom/android/internal/os/KernelCpuBpfTracking; 11
+Lcom/android/internal/statusbar/NotificationVisibility$NotificationLocation; 11
+Landroid/hardware/camera2/CameraManager$CameraManagerGlobal; 11
+Landroid/os/ServiceSpecificException; 11
+Landroid/net/Uri$PathPart;.NULL:Landroid/net/Uri$PathPart; 11
+Landroid/app/ActivityManagerInternal; 11
+Landroid/media/AudioSystem; 11
+Landroid/service/dreams/DreamManagerInternal; 11
+Landroid/debug/AdbManagerInternal; 11
+Landroid/graphics/Bitmap$CompressFormat; 11
+Landroid/hardware/location/NanoAppMessage; 11
+Landroid/os/storage/StorageManagerInternal; 11
+Landroid/app/AppOpsManagerInternal; 11
+Ljava/security/cert/CertificateException; 11
+Ldalvik/system/VMRuntime; 11
+Landroid/content/pm/SigningInfo; 11
+Landroid/view/KeyEvent; 11
+Lcom/android/internal/view/WindowManagerPolicyThread; 11
+Landroid/graphics/Region;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 11
+Landroid/content/res/ResourceTimer; 11
+Landroid/view/autofill/AutofillManagerInternal; 11
+Lcom/android/internal/util/Parcelling$Cache;.sCache:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object; 11
+Landroid/graphics/Region;.sPool:Landroid/util/Pools$SynchronizedPool; 11
+Landroid/app/LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0; 11
+Lcom/android/server/LocalServices;.sLocalServiceObjects:Landroid/util/ArrayMap; 11
+Landroid/app/admin/DevicePolicyManagerInternal$OnCrossProfileWidgetProvidersChangeListener; 11
+Landroid/accounts/AccountManagerInternal$OnAppPermissionChangeListener; 11
+Landroid/content/pm/PermissionInfo; 11
+Landroid/view/WindowManagerPolicyConstants$PointerEventListener; 11
+Landroid/os/UEventObserver; 11
+Landroid/media/AudioManagerInternal$RingerModeDelegate; 11
+Landroid/view/Display$HdrCapabilities; 11
+Landroid/service/notification/Condition; 11
+Landroid/content/pm/UserPackage; 11
+Landroid/app/AppOpsManager$SamplingStrategy; 11
+Landroid/telephony/ServiceState; 11
+Landroid/app/servertransaction/PauseActivityItem; 11
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sMessageCallbacksPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;.mLock:Ljava/lang/Object; 11
+Landroid/view/KeyCharacterMap$FallbackAction; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringArray; 11
+Landroid/hardware/display/DeviceProductInfo; 11
+Lcom/android/internal/util/Parcelling$Cache;.sCache:Landroid/util/ArrayMap;.mHashes:[I 11
+Landroid/content/pm/RegisteredServicesCache$2; 11
+Landroid/content/pm/PackageManager;.sCacheAutoCorker:Landroid/app/PropertyInvalidatedCache$AutoCorker; 11
+Landroid/app/PropertyInvalidatedCache;.sCorks:Ljava/util/HashMap; 11
+Landroid/service/notification/StatusBarNotification; 11
+Landroid/app/servertransaction/ConfigurationChangeItem; 11
+Landroid/app/ActivityManager$RecentTaskInfo; 11
+Landroid/app/Notification; 11
+Landroid/app/servertransaction/DestroyActivityItem; 11
+Landroid/webkit/WebViewLibraryLoader$RelroFileCreator; 11
+Landroid/net/metrics/NetworkEvent; 11
+Landroid/media/AudioPlaybackConfiguration; 11
+Landroid/accessibilityservice/AccessibilityServiceInfo; 11
+Landroid/hardware/display/DeviceProductInfo$ManufactureDate; 11
+Landroid/os/storage/StorageVolume; 11
+Landroid/os/BatteryManagerInternal; 11
+Landroid/appwidget/AppWidgetManagerInternal; 11
+Landroid/app/servertransaction/NewIntentItem; 11
+Landroid/content/pm/ShortcutServiceInternal; 11
+Landroid/app/assist/ActivityId; 11
+Landroid/window/DisplayAreaAppearedInfo; 11
+Landroid/os/Process;.ZYGOTE_PROCESS:Landroid/os/ZygoteProcess;.mLock:Ljava/lang/Object; 11
+Landroid/app/usage/UsageStats; 11
+Landroid/app/Notification$MediaStyle; 11
+Landroid/media/AudioSystem$DynamicPolicyCallback; 11
+Landroid/content/pm/ProviderInfo; 11
+Landroid/os/PowerManagerInternal; 11
+Landroid/service/voice/VoiceInteractionManagerInternal; 11
+Landroid/content/pm/FeatureInfo; 11
+Landroid/app/servertransaction/TopResumedActivityChangeItem; 11
+Landroid/app/Notification$DecoratedMediaCustomViewStyle; 11
+Landroid/appwidget/AppWidgetProviderInfo; 11
+Landroid/app/AppOpsManager$NoteOpEvent; 11
+Landroid/graphics/GraphicsStatsService; 11
+Landroid/view/DisplayAddress$Physical; 11
+Landroid/content/ComponentName$WithComponentName; 11
+Landroid/app/admin/DevicePolicyManagerInternal; 11
+Landroid/os/ResultReceiver$MyResultReceiver; 11
+Landroid/content/ContentProviderClient; 11
+Landroid/content/pm/RegisteredServicesCache$1; 11
+Landroid/app/PendingIntent$FinishedDispatcher; 11
+Landroid/location/LocationManager; 11
+Landroid/hardware/location/ContextHubInfo; 11
+Landroid/content/pm/ShortcutServiceInternal$ShortcutChangeListener; 11
+Lcom/android/server/usage/AppStandbyInternal; 11
+Landroid/content/pm/RegisteredServicesCacheListener; 11
+Landroid/app/servertransaction/LaunchActivityItem; 11
+Landroid/content/pm/BaseParceledListSlice$1; 11
+Landroid/annotation/StringRes; 11
+Lcom/android/internal/R$styleable;.Window:[I 11
+Landroid/service/notification/ZenModeConfig; 11
+Landroid/telecom/Logging/SessionManager$ISessionListener; 11
+Landroid/app/time/TimeZoneConfiguration; 11
+Landroid/net/metrics/ValidationProbeEvent; 11
+Landroid/content/pm/PackageInstaller$SessionInfo; 11
+Landroid/content/pm/UserPackage;.sCache:Landroid/util/SparseArrayMap;.mData:Landroid/util/SparseArray; 11
+Landroid/content/pm/PermissionGroupInfo; 11
+Landroid/hardware/sidekick/SidekickInternal; 11
+Lcom/android/internal/widget/ButtonBarLayout; 11
+Landroid/content/pm/LauncherActivityInfoInternal; 11
+Lcom/android/internal/util/Parcelling$Cache;.sCache:Landroid/util/ArrayMap; 11
+Lcom/android/internal/widget/LockSettingsInternal; 11
+Landroid/media/AudioManagerInternal; 11
+Landroid/app/AppOpsManager$AttributedOpEntry; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringList; 11
+Landroid/telecom/Log; 11
+Landroid/app/time/TimeZoneCapabilities; 11
+Landroid/attention/AttentionManagerInternal; 11
+Landroid/view/WindowManagerPolicyConstants; 11
+Landroid/content/pm/CrossProfileAppsInternal; 11
+Landroid/hardware/location/GeofenceHardwareService; 11
+Landroid/content/pm/dex/ArtManagerInternal; 11
+Landroid/net/metrics/IpReachabilityEvent; 11
+Landroid/content/pm/LauncherApps$ShortcutQuery$QueryFlags; 11
+Landroid/media/AudioAttributes; 11
+Landroid/app/PropertyInvalidatedCache$AutoCorker$1; 11
+Landroid/net/metrics/ApfProgramEvent; 11
+Landroid/content/pm/SigningDetails; 11
+Lcom/android/internal/protolog/ProtoLogImpl; 11
+Landroid/hardware/biometrics/ComponentInfoInternal; 11
+Lcom/android/internal/util/ToBooleanFunction; 11
+Landroid/app/ActivityThread$H; 11
+Landroid/hardware/location/GeofenceHardwareImpl; 11
+Landroid/net/wifi/nl80211/WifiNl80211Manager$ScanEventHandler; 11
+Landroid/util/NtpTrustedTime; 11
+Landroid/hardware/soundtrigger/SoundTrigger$StatusListener; 11
+Lcom/android/internal/app/procstats/AssociationState;.sTmpSourceKey:Lcom/android/internal/app/procstats/AssociationState$SourceKey; 11
+Ljava/util/zip/ZipFile$ZipFileInflaterInputStream; 11
+Landroid/app/job/JobInfo; 11
+Lcom/android/internal/content/om/OverlayConfig; 11
+Landroid/webkit/WebViewZygote; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringSet; 11
+Lcom/android/internal/infra/AbstractRemoteService$VultureCallback; 11
+Landroid/permission/PermissionManagerInternal; 11
+Lcom/android/server/WidgetBackupProvider; 11
+Landroid/window/WindowOnBackInvokedDispatcher$OnBackInvokedCallbackWrapper; 11
+Landroid/app/PropertyInvalidatedCache;.sCorkedInvalidates:Ljava/util/HashMap; 11
+Landroid/media/AudioPlaybackConfiguration$PlayerDeathMonitor; 11
+Landroid/net/wifi/nl80211/WifiNl80211Manager$ScanEventCallback; 11
+Landroid/service/notification/NotificationListenerService$RankingMap; 11
+Landroid/os/UserHandle;.sExtraUserHandleCache:Landroid/util/SparseArray; 11
+Ljava/time/DateTimeException; 11
+Ljava/lang/NumberFormatException; 11
+Ljava/security/Provider;.knownEngines:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.125:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 11
+Landroid/app/LoadedApk$ServiceDispatcher$RunConnection; 11
+Landroid/view/RoundedCorners; 11
+Landroid/os/Process;.ZYGOTE_PROCESS:Landroid/os/ZygoteProcess; 11
+Landroid/media/audiopolicy/AudioVolumeGroup; 11
+Landroid/media/AudioSystem$ErrorCallback; 11
+Landroid/app/servertransaction/ActivityResultItem; 11
+Lcom/android/internal/widget/DialogTitle; 11
+Lcom/android/internal/os/StoragedUidIoStatsReader$Callback; 11
+Landroid/view/ViewRootImpl$W; 11
+Landroid/app/ServiceStartArgs; 11
+Landroid/window/TaskAppearedInfo; 11
+Lcom/android/internal/listeners/ListenerExecutor$FailureCallback; 11
+Landroid/app/ApplicationExitInfo; 11
+Landroid/content/pm/PackageManager;.sCacheAutoCorker:Landroid/app/PropertyInvalidatedCache$AutoCorker;.mLock:Ljava/lang/Object; 11
+Lcom/android/internal/util/Parcelling$BuiltIn$ForInternedStringValueMap; 11
+Landroid/content/pm/ResolveInfo; 11
+Lcom/android/internal/display/BrightnessSynchronizer; 11
+Landroid/window/IOnBackInvokedCallback$Stub$Proxy; 12
+Landroid/graphics/drawable/PictureDrawable; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.126:Ljava/lang/Byte; 13
+Landroid/view/ViewDebug$ExportedProperty; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.41:Ljava/lang/Byte; 13
+Landroid/view/inputmethod/DeleteGesture; 13
+Landroid/view/ViewDebug$IntToString; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.56:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.65:Ljava/lang/Byte; 13
+Landroid/webkit/WebViewFactory;.sProviderLock:Ljava/lang/Object; 13
+Ljava/lang/IllegalAccessError; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.51:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.52:Ljava/lang/Byte; 13
+Landroid/view/inputmethod/DeleteRangeGesture; 13
+Landroid/window/WindowContext; 13
+Ljava/util/concurrent/ConcurrentSkipListMap$Node; 13
+Landroid/view/inputmethod/SelectRangeGesture; 13
+Landroid/util/MalformedJsonException; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.131:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.120:Ljava/lang/Byte; 13
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 13
+Ljava/nio/file/StandardOpenOption;.TRUNCATE_EXISTING:Ljava/nio/file/StandardOpenOption; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.121:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.16:Ljava/lang/Byte; 13
+Ljava/util/concurrent/ConcurrentSkipListMap$Index; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.139:Ljava/lang/Byte; 13
+Landroid/view/ViewDebug$FlagToString; 13
+Landroid/view/inputmethod/SelectGesture; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.20:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.94:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.64:Ljava/lang/Byte; 13
+Landroid/webkit/WebViewFactoryProvider$Statics; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.95:Ljava/lang/Byte; 13
+Landroid/service/media/MediaBrowserService$ServiceBinder$1; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.7:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.23:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.46:Ljava/lang/Byte; 13
+Landroid/provider/Settings$SettingNotFoundException; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.74:Ljava/lang/Byte; 13
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.8:Ljava/lang/Byte; 13
+Landroid/widget/TextView;.TEMP_POSITION:[F 13
+Ljava/io/ByteArrayInputStream; 14
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.93:Ljava/lang/Byte; 14
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.134:Ljava/lang/Byte; 14
+Landroid/text/style/ImageSpan; 14
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.154:Ljava/lang/Byte; 15
+Landroid/view/TextureView$SurfaceTextureListener; 16
+Landroid/media/AudioManager$OnAudioFocusChangeListener; 17
+Ljava/util/Locale;.JAPAN:Ljava/util/Locale; 18
+Ljava/util/Locale;.GERMANY:Ljava/util/Locale; 19
+Ljava/util/Locale;.CANADA_FRENCH:Ljava/util/Locale; 20
+Ljava/util/Locale;.ITALY:Ljava/util/Locale; 20
+Ljava/util/Locale;.FRANCE:Ljava/util/Locale; 20
+Ljava/util/Locale;.UK:Ljava/util/Locale; 21
+Ljava/util/Locale;.CANADA:Ljava/util/Locale; 21
+Ljava/util/Locale$Cache;.LOCALECACHE:Ljava/util/Locale$Cache;.map:Ljava/util/concurrent/ConcurrentMap; 22
+Ljava/lang/IllegalStateException; 23
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sMessageCallbacksPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool; 24
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sMessageCallbacksPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;.mPool:[Ljava/lang/Object; 24
+Landroid/media/MediaRouter$WifiDisplayStatusChangedReceiver; 25
+Landroid/media/MediaRouter$VolumeChangeReceiver; 25
+Landroid/app/AppOpsManager$OnOpActiveChangedListener; 26
+Landroid/media/PlayerBase; 27
+Landroid/content/pm/Checksum$Type; 28
+Ljava/lang/Class; 29
+Landroid/widget/MediaController$MediaPlayerControl; 30
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.135:Ljava/lang/Long; 30
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.152:Ljava/lang/Long; 30
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.215:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.206:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.137:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.203:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.213:Ljava/lang/Byte; 31
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.549:Ljava/lang/Long; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.201:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.249:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.163:Ljava/lang/Byte; 31
+Ljava/util/HashMap; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.210:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.161:Ljava/lang/Byte; 31
+Landroid/icu/text/MeasureFormat;.hmsTo012:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.0:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.199:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.248:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.252:Ljava/lang/Byte; 31
+Lcom/android/ims/rcs/uce/UceDeviceState;.DEVICE_STATE_DESCRIPTION:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.3:Ljava/util/HashMap$Node;.key:Ljava/lang/Object; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.159:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.217:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.200:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.240:Ljava/lang/Byte; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.198:Ljava/lang/Byte; 31
+Lcom/android/ims/rcs/uce/UceDeviceState;.DEVICE_STATE_DESCRIPTION:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.4:Ljava/util/HashMap$Node;.key:Ljava/lang/Object; 31
+Landroid/content/pm/PackageManager$OnChecksumsReadyListener; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.193:Ljava/lang/Byte; 31
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.228:Ljava/lang/Long; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.236:Ljava/lang/Byte; 31
+Landroid/telephony/ims/ImsService;.CAPABILITIES_LOG_MAP:Ljava/util/Map;.table:[Ljava/lang/Object;.2:Ljava/lang/Long; 31
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.211:Ljava/lang/Byte; 31
+Landroid/view/SurfaceView; 32
+Landroid/view/ViewStub$OnInflateListener; 33
+Landroid/graphics/drawable/DrawableInflater;.CONSTRUCTOR_MAP:Ljava/util/HashMap; 34
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.245:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.232:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.12:Ljava/lang/Byte; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.170:Ljava/lang/Long; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.183:Ljava/lang/Long; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.246:Ljava/lang/Byte; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.168:Ljava/lang/Long; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.72:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.243:Ljava/lang/Byte; 35
+Ljava/util/WeakHashMap;.NULL_KEY:Ljava/lang/Object; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.235:Ljava/lang/Byte; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.147:Ljava/lang/Long; 35
+Ljava/io/InterruptedIOException; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.184:Ljava/lang/Long; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.165:Ljava/lang/Long; 35
+Landroid/text/style/ForegroundColorSpan; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.176:Ljava/lang/Long; 35
+Ljava/lang/Long$LongCache;.archivedCache:[Ljava/lang/Long;.173:Ljava/lang/Long; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.181:Ljava/lang/Byte; 35
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.157:Ljava/lang/Byte; 35
+Landroid/content/res/AssetManager$AssetInputStream; 35
+Landroid/graphics/drawable/TransitionDrawable; 36
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1:Ljava/lang/Boolean; 37
+Landroid/view/ViewOverlay$OverlayViewGroup; 38
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.11:Ljava/lang/Boolean; 39
+Ljava/util/Observer; 40
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.129:Ljava/lang/Byte; 41
+[Ljava/lang/Byte; 41
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.144:Ljava/lang/Byte; 41
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.164:Ljava/lang/Byte; 42
+Landroid/view/OrientationEventListener; 43
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.195:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.233:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.229:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.128:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.242:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.196:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.208:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.212:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.228:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.205:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.197:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.204:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.207:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.223:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.244:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.174:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.194:Ljava/lang/Byte; 44
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.225:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.239:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.238:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.227:Ljava/lang/Byte; 45
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.152:Ljava/lang/Byte; 46
+Landroid/app/RemoteAction; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.168:Ljava/lang/Byte; 46
+Landroid/text/style/QuoteSpan; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.54:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.124:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.142:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.190:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.114:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.69:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.30:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.133:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.49:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.58:Ljava/lang/Byte; 46
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.143:Ljava/lang/Byte; 47
+Landroid/icu/text/RelativeDateTimeFormatter$AbsoluteUnit; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.82:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.140:Ljava/lang/Byte; 47
+Landroid/icu/text/RelativeDateTimeFormatter;.fallbackCache:[Landroid/icu/text/RelativeDateTimeFormatter$Style; 47
+Landroid/icu/text/RelativeDateTimeFormatter$Style; 47
+Landroid/icu/text/RelativeDateTimeFormatter;.cache:Landroid/icu/text/RelativeDateTimeFormatter$Cache;.cache:Landroid/icu/impl/CacheBase;.map:Ljava/util/concurrent/ConcurrentHashMap; 47
+Landroid/icu/text/RelativeDateTimeFormatter$RelativeUnit; 47
+Landroid/icu/text/RelativeDateTimeFormatter$Direction; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.130:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.43:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.146:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.138:Ljava/lang/Byte; 47
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.136:Ljava/lang/Byte; 48
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.0:Ljava/lang/Byte; 49
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.160:Ljava/lang/Byte; 49
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.169:Ljava/lang/Byte; 50
+Landroid/widget/Spinner; 50
+Landroid/widget/MultiAutoCompleteTextView; 50
+Ljava/util/ArrayList; 50
+Landroid/widget/CheckBox; 50
+Ljava/io/Serializable; 50
+Landroid/widget/RatingBar; 50
+Ljava/lang/Byte$ByteCache;.archivedCache:[Ljava/lang/Byte;.132:Ljava/lang/Byte; 50
+Landroid/widget/AutoCompleteTextView; 50
+Ljava/util/concurrent/ConcurrentLinkedDeque$Node; 50
+[Ljava/lang/Object; 50
+Landroid/widget/SeekBar; 51
+Ljava/lang/Void; 52
+Landroid/app/ActivityTaskManager;.sInstance:Landroid/util/Singleton; 53
+Landroid/view/ViewRootImpl$$ExternalSyntheticLambda11; 54
+Landroid/view/ViewTreeObserver$OnWindowFocusChangeListener; 55
+Landroid/view/InsetsAnimationThread; 56
+Lcom/android/internal/jank/InteractionJankMonitor$InstanceHolder; 57
+Lcom/android/internal/jank/InteractionJankMonitor; 57
+Landroid/hardware/camera2/CameraCharacteristics;.FLASH_INFO_AVAILABLE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 58
+Landroid/hardware/display/NightDisplayListener$Callback; 59
+Landroid/media/MediaRouter2Manager; 59
+Landroid/os/HandlerExecutor; 59
+Landroid/os/strictmode/LeakedClosableViolation; 60
+Lcom/android/internal/logging/MetricsLogger; 60
+Lcom/android/internal/os/PowerProfile;.sPowerItemMap:Ljava/util/HashMap; 61
+Lcom/android/internal/os/PowerProfile;.sPowerArrayMap:Ljava/util/HashMap; 61
+Lcom/android/internal/os/PowerProfile;.sModemPowerProfile:Lcom/android/internal/power/ModemPowerProfile;.mPowerConstants:Landroid/util/SparseDoubleArray;.mValues:Landroid/util/SparseLongArray; 61
+Landroid/content/IntentFilter; 62
+Landroid/telecom/TelecomManager; 63
+Ljava/lang/IllegalArgumentException; 64
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.1:Ljava/util/WeakHashMap$Entry;.referent:Ljava/lang/Object; 65
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.1:Ljava/util/WeakHashMap$Entry;.referent:Ljava/lang/Object;.mCache:Ljava/util/LinkedHashMap; 65
+Landroid/telephony/VisualVoicemailSmsFilterSettings;.DEFAULT_ORIGINATING_NUMBERS:Ljava/util/List; 66
+Ljava/util/AbstractList; 68
+Ljava/util/AbstractCollection; 68
+Ljava/util/Collections$EmptyList; 69
+Ljava/lang/StackTraceElement; 69
+[Ljava/lang/StackTraceElement; 69
+Landroid/os/strictmode/Violation; 70
+Ljava/util/List; 71
+Ljava/lang/String; 72
+Ljava/io/ObjectInputStream; 73
+Ljava/io/ObjectStreamClass$Caches;.localDescs:Ljava/util/concurrent/ConcurrentMap; 73
+Ljava/io/ObjectStreamClass$Caches;.reflectors:Ljava/util/concurrent/ConcurrentMap; 73
+Ljava/io/ObjectOutputStream; 73
+Ljava/lang/Number; 74
+Ljava/math/BigInteger; 75
+[B 76
+Landroid/os/Handler; 77
+Landroid/view/accessibility/AccessibilityManager; 78
+Landroid/view/ViewConfiguration;.sConfigurations:Landroid/util/SparseArray;.mKeys:[I 79
+Landroid/view/ViewConfiguration;.sConfigurations:Landroid/util/SparseArray;.mValues:[Ljava/lang/Object; 79
+Landroid/view/ViewConfiguration;.sConfigurations:Landroid/util/SparseArray; 79
+Landroid/widget/FrameLayout; 80
+Lcom/android/internal/inputmethod/ImeTracing; 80
+Lcom/android/internal/policy/DecorView; 80
+Landroid/view/accessibility/AccessibilityNodeIdManager; 80
+Landroid/view/ViewTreeObserver; 80
+Landroid/view/ViewRootImpl; 80
+Landroid/os/SystemProperties;.sChangeCallbacks:Ljava/util/ArrayList; 80
+Landroid/transition/ChangeTransform; 80
+Landroid/window/SurfaceSyncGroup; 80
+Landroid/transition/ChangeClipBounds; 80
+Landroid/view/SurfaceControlRegistry; 80
+Landroid/transition/ChangeImageTransform; 80
+Landroid/widget/LinearLayout; 80
+Landroid/view/ViewStub; 81
+Landroid/text/TextLine;.sCached:[Landroid/text/TextLine; 82
+Landroid/text/TextUtils; 82
+Landroid/graphics/TemporaryBuffer; 82
+Landroid/content/res/ColorStateList;.sCache:Landroid/util/SparseArray; 83
+Landroid/text/Layout;.sTempRect:Landroid/graphics/Rect; 84
+Landroid/widget/ImageView; 85
+Landroid/graphics/drawable/ColorDrawable; 86
+Landroid/os/StrictMode$InstanceTracker;.sInstanceCounts:Ljava/util/HashMap; 87
+Landroid/app/ActivityClient;.INTERFACE_SINGLETON:Landroid/app/ActivityClient$ActivityClientControllerSingleton; 88
+Landroid/app/ActivityClient;.sInstance:Landroid/util/Singleton; 88
+Landroid/view/AbsSavedState$1; 89
+Landroid/app/FragmentManagerState; 90
+Landroid/window/OnBackAnimationCallback; 91
+Landroid/animation/AnimatorInflater;.sTmpTypedValue:Landroid/util/TypedValue; 92
+Landroid/graphics/drawable/RippleDrawable; 93
+Landroid/view/inputmethod/IInputMethodManagerGlobalInvoker; 94
+Landroid/app/ActivityTaskManager;.IActivityTaskManagerSingleton:Landroid/util/Singleton; 95
+Landroid/view/Choreographer; 96
+Lcom/android/internal/os/SomeArgs; 97
+Landroid/graphics/Bitmap; 98
+Landroid/view/autofill/AutofillId; 99
+Landroid/view/inputmethod/BaseInputConnection;.COMPOSING:Ljava/lang/Object; 100
+Landroid/text/Selection;.SELECTION_MEMORY:Ljava/lang/Object; 101
+Landroid/text/Selection;.SELECTION_END:Ljava/lang/Object; 101
+Landroid/text/Selection;.SELECTION_START:Ljava/lang/Object; 101
+Landroid/text/SpannableStringBuilder;.sCachedIntBuffer:[[I 102
+Landroid/text/Selection$MemoryTextWatcher; 103
+Landroid/text/SpanWatcher; 104
+Lcom/android/internal/util/ArrayUtils;.sCache:[Ljava/lang/Object; 105
+Ljava/lang/Integer;.SMALL_NEG_VALUES:[Ljava/lang/String; 106
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 107
+Lsun/nio/ch/SharedFileLockTable;.lockMap:Ljava/util/concurrent/ConcurrentHashMap; 108
+Lsun/nio/ch/FileChannelImpl; 108
+Landroid/database/sqlite/SQLiteDatabase$CursorFactory; 109
+Landroid/database/sqlite/SQLiteDebug$NoPreloadHolder; 110
+Landroid/database/sqlite/SQLiteCompatibilityWalFlags; 110
+Landroid/database/sqlite/SQLiteGlobal; 110
+Landroid/database/CursorWindow; 111
+Landroid/content/ContentResolver; 112
+Ljava/nio/charset/Charset; 113
+Landroid/app/ContextImpl; 114
+Ljava/util/concurrent/Executors$DefaultThreadFactory;.poolNumber:Ljava/util/concurrent/atomic/AtomicInteger; 115
+Landroid/content/pm/PackageManager;.sPackageInfoCache:Landroid/app/PropertyInvalidatedCache;.mCache:Ljava/util/LinkedHashMap; 116
+Landroid/content/pm/PackageManager;.sApplicationInfoCache:Landroid/app/PropertyInvalidatedCache;.mCache:Ljava/util/LinkedHashMap; 117
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.systemContext:Ljava/util/logging/LogManager$LoggerContext;.namedLoggers:Ljava/util/Hashtable;.table:[Ljava/util/Hashtable$HashtableEntry; 118
+Landroid/ddm/DdmHandleAppName; 118
+Landroid/provider/DeviceConfigInitializer; 118
+Lsun/misc/Cleaner; 118
+Ldalvik/system/CloseGuard; 118
+Landroid/graphics/Typeface; 118
+Landroid/os/BinderProxy;.sProxyMap:Landroid/os/BinderProxy$ProxyMap;.mMainIndexKeys:[[Ljava/lang/Long; 118
+Landroid/permission/PermissionManager; 118
+Landroid/media/MediaFrameworkPlatformInitializer; 118
+Ljava/util/TimeZone; 118
+Landroid/os/Environment; 118
+Landroid/compat/Compatibility; 118
+Landroid/os/ServiceManager; 118
+Landroid/content/pm/PackageManager;.sApplicationInfoCache:Landroid/app/PropertyInvalidatedCache; 118
+Ljava/util/Locale$NoImagePreloadHolder; 118
+Ljava/lang/System; 118
+Lcom/android/internal/os/RuntimeInit; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.systemContext:Ljava/util/logging/LogManager$LoggerContext;.namedLoggers:Ljava/util/Hashtable; 118
+Ldalvik/system/VMRuntime;.THE_ONE:Ldalvik/system/VMRuntime; 118
+Landroid/view/View; 118
+Landroid/hardware/display/DisplayManagerGlobal; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager; 118
+Landroid/telephony/TelephonyFrameworkInitializer; 118
+Landroid/se/omapi/SeFrameworkInitializer; 118
+Landroid/app/LoadedApk;.sApplications:Landroid/util/ArrayMap;.mHashes:[I 118
+Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder; 118
+Landroid/security/net/config/ApplicationConfig; 118
+Landroid/content/res/Resources;.sResourcesHistory:Ljava/util/Set;.c:Ljava/util/Collection;.m:Ljava/util/Map; 118
+Ljava/util/Locale; 118
+Landroid/content/res/Resources;.sResourcesHistory:Ljava/util/Set;.c:Ljava/util/Collection;.m:Ljava/util/Map;.table:[Ljava/util/WeakHashMap$Entry; 118
+Ljava/security/Provider; 118
+Ldalvik/system/ZygoteHooks; 118
+Landroid/os/Message; 118
+Landroid/app/LoadedApk;.sApplications:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object; 118
+Landroid/app/LoadedApk;.sApplications:Landroid/util/ArrayMap; 118
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.userContext:Ljava/util/logging/LogManager$LoggerContext;.namedLoggers:Ljava/util/Hashtable; 118
+Ljava/lang/ThreadGroup;.mainThreadGroup:Ljava/lang/ThreadGroup; 118
+Ldalvik/system/RuntimeHooks; 118
+Landroid/nfc/NfcFrameworkInitializer; 118
+Landroid/os/Looper; 118
+Landroid/os/LocaleList; 118
+Ldalvik/system/SocketTagger; 118
+Landroid/icu/util/TimeZone; 118
+Landroid/util/ArraySet; 118
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.systemContext:Ljava/util/logging/LogManager$LoggerContext;.root:Ljava/util/logging/LogManager$LogNode; 118
+Landroid/os/BinderProxy;.sProxyMap:Landroid/os/BinderProxy$ProxyMap;.mMainIndexValues:[Ljava/util/ArrayList; 118
+Ljava/util/Random;.seedUniquifier:Ljava/util/concurrent/atomic/AtomicLong; 118
+Landroid/app/ActivityThread; 118
+Landroid/os/Binder; 118
+Ljava/lang/ThreadLocal;.nextHashCode:Ljava/util/concurrent/atomic/AtomicInteger; 119
+Landroid/os/Parcel; 120
+Landroid/system/UnixSocketAddress; 120
+Ljava/lang/ThreadGroup;.systemThreadGroup:Ljava/lang/ThreadGroup; 120
+Ljava/lang/Daemons$FinalizerDaemon;.INSTANCE:Ljava/lang/Daemons$FinalizerDaemon; 120
+Landroid/os/Parcel;.sPairedCreators:Ljava/util/HashMap; 120
+Ljava/lang/Thread; 120
+Landroid/os/Parcel;.mCreators:Ljava/util/HashMap; 120
+Ljava/lang/Daemons$FinalizerDaemon;.INSTANCE:Ljava/lang/Daemons$FinalizerDaemon;.progressCounter:Ljava/util/concurrent/atomic/AtomicInteger; 120
+Landroid/system/StructPollfd; 120
+Ljava/lang/Daemons$HeapTaskDaemon;.INSTANCE:Ljava/lang/Daemons$HeapTaskDaemon; 120
+Landroid/system/StructTimeval; 120
+Ldalvik/system/VMRuntime;.THE_ONE:Ldalvik/system/VMRuntime;.allocationCount:Ljava/util/concurrent/atomic/AtomicInteger; 120
+Ljava/lang/Daemons$ReferenceQueueDaemon;.INSTANCE:Ljava/lang/Daemons$ReferenceQueueDaemon;.progressCounter:Ljava/util/concurrent/atomic/AtomicInteger; 120
+Landroid/os/GraphicsEnvironment;.sInstance:Landroid/os/GraphicsEnvironment; 120
+Ljava/lang/Daemons$FinalizerWatchdogDaemon;.INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon; 120
+Ljava/lang/ref/FinalizerReference; 120
+Landroid/os/Process; 120
+Ljava/lang/Daemons$ReferenceQueueDaemon;.INSTANCE:Ljava/lang/Daemons$ReferenceQueueDaemon; 120
+Lcom/android/internal/os/BinderInternal; 120
+Landroid/app/ApplicationLoaders;.gApplicationLoaders:Landroid/app/ApplicationLoaders;.mLoaders:Landroid/util/ArrayMap; 121
+Landroid/app/DexLoadReporter;.INSTANCE:Landroid/app/DexLoadReporter;.mDataDirs:Ljava/util/Set;.map:Ljava/util/HashMap; 122
+Ldalvik/system/BaseDexClassLoader; 122
+Landroid/renderscript/RenderScriptCacheDir; 122
+Landroid/graphics/Compatibility; 123
+Llibcore/io/Libcore; 123
+Landroid/provider/FontsContract; 123
+Ljava/security/Security;.version:Ljava/util/concurrent/atomic/AtomicInteger; 123
+Llibcore/net/NetworkSecurityPolicy; 123
+Lsun/security/jca/Providers; 123
+Landroid/graphics/Canvas; 123
+Landroid/os/StrictMode; 124
+Landroid/content/pm/PackageManager;.sPackageInfoCache:Landroid/app/PropertyInvalidatedCache; 125
+Lcom/android/internal/os/StatsdHiddenApiUsageLogger;.sInstance:Lcom/android/internal/os/StatsdHiddenApiUsageLogger; 126
+Ljava/util/logging/LogManager;.manager:Ljava/util/logging/LogManager;.loggerRefQueue:Ljava/lang/ref/ReferenceQueue; 127
+Landroid/view/WindowManagerGlobal; 128
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool; 129
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;.sPool:Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;.mPool:[Ljava/lang/Object; 129
+Landroid/view/inputmethod/InputMethodManager; 130
+Landroid/media/MediaRouter; 131
+Landroid/hardware/SensorPrivacyManager; 132
+Landroid/os/storage/StorageManager; 133
+Landroid/view/contentcapture/ContentCaptureManager; 134
+Landroid/hardware/input/InputManager; 134
+Landroid/app/people/PeopleManager; 134
+Landroid/media/session/MediaSessionManager; 134
+Landroid/security/attestationverification/AttestationVerificationManager; 134
+Landroid/net/vcn/VcnManager; 134
+Landroid/os/RecoverySystem; 134
+Landroid/net/NetworkPolicyManager; 134
+Landroid/net/wifi/sharedconnectivity/app/SharedConnectivityManager; 134
+Landroid/permission/PermissionControllerManager; 134
+Landroid/app/tare/EconomyManager; 134
+Landroid/view/translation/TranslationManager; 134
+Landroid/view/textclassifier/TextClassificationManager; 134
+Landroid/view/autofill/AutofillManager; 134
+Landroid/os/SystemConfigManager; 134
+Landroid/view/LayoutInflater; 134
+Landroid/credentials/CredentialManager; 134
+Landroid/service/persistentdata/PersistentDataBlockManager; 134
+Landroid/view/textservice/TextServicesManager; 134
+Landroid/app/admin/DevicePolicyManager; 134
+Ljava/lang/StackStreamFactory; 134
+Landroid/view/WindowManager; 134
+Landroid/app/contentsuggestions/ContentSuggestionsManager; 134
+Landroid/media/tv/tunerresourcemanager/TunerResourceManager; 134
+Landroid/telephony/SubscriptionManager; 134
+Landroid/os/HardwarePropertiesManager; 134
+Landroid/media/AudioManager; 135
+Landroid/telephony/TelephonyManager; 136
+Landroid/util/ArrayMap; 137
+Landroid/app/QueuedWork; 138
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.0:Ljava/util/WeakHashMap$Entry; 139
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap; 140
+Ljava/util/concurrent/ScheduledThreadPoolExecutor;.sequencer:Ljava/util/concurrent/atomic/AtomicLong; 141
+Landroid/util/Log; 142
+Ljava/util/Collections$SynchronizedCollection; 143
+Ljava/util/Set; 143
+Ljava/util/Collections$SynchronizedSet; 143
+Ljava/util/Collection; 143
+Ljava/lang/Integer;.SMALL_NONNEG_VALUES:[Ljava/lang/String; 144
+Landroid/content/ComponentName; 145
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle; 146
+Landroid/os/PersistableBundle;.EMPTY:Landroid/os/PersistableBundle; 147
+Landroid/icu/impl/locale/BaseLocale;.CACHE:Landroid/icu/impl/locale/BaseLocale$Cache;._map:Ljava/util/concurrent/ConcurrentHashMap; 148
+Ljava/util/GregorianCalendar; 149
+Ljava/text/DontCareFieldPosition;.INSTANCE:Ljava/text/FieldPosition; 150
+Landroid/app/UiModeManager; 151
+Ljdk/internal/access/SharedSecrets; 152
+Landroid/icu/impl/ZoneMeta;.CANONICAL_ID_CACHE:Landroid/icu/impl/ICUCache; 153
+Landroid/icu/impl/ZoneMeta;.SYSTEM_ZONE_CACHE:Landroid/icu/impl/ZoneMeta$SystemTimeZoneCache;.map:Ljava/util/concurrent/ConcurrentHashMap; 154
+Ljava/time/ZoneOffset;.ID_CACHE:Ljava/util/concurrent/ConcurrentMap; 155
+Ljava/time/ZoneOffset;.ID_CACHE:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 155
+Ljava/time/ZoneOffset;.SECONDS_CACHE:Ljava/util/concurrent/ConcurrentMap; 155
+Ljava/time/ZoneOffset;.SECONDS_CACHE:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.0:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 155
+Ljava/time/ZoneOffset;.SECONDS_CACHE:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 155
+Landroid/widget/TextView; 156
+Landroid/view/ViewGroup$ChildListForAutoFillOrContentCapture;.sPool:Landroid/util/Pools$SimplePool;.mPool:[Ljava/lang/Object; 157
+Landroid/view/ViewGroup$ChildListForAutoFillOrContentCapture;.sPool:Landroid/util/Pools$SimplePool; 157
+Landroid/view/ViewGroup; 158
+Landroid/graphics/Rect; 159
+Landroid/view/View$BaseSavedState; 160
+Landroid/widget/Button; 161
+Landroid/widget/ImageButton; 162
+Landroid/view/View$OnHoverListener; 163
+Landroid/widget/Toolbar; 164
+Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal; 165
+Landroid/app/WallpaperManager; 166
+Landroid/graphics/ColorSpace$Model;.RGB:Landroid/graphics/ColorSpace$Model; 166
+Landroid/graphics/drawable/AdaptiveIconDrawable; 167
+Landroid/animation/ValueAnimator$DurationScaleChangeListener; 168
+Landroid/widget/Toast; 168
+Landroid/app/smartspace/SmartspaceSession$OnTargetsAvailableListener; 168
+Landroid/view/CrossWindowBlurListeners; 168
+Landroid/app/servertransaction/ActivityRelaunchItem; 169
+[Ljava/util/concurrent/ForkJoinTask; 169
+Landroid/view/WindowManager$LayoutParams; 169
+Ljava/util/concurrent/ForkJoinPool$WorkQueue; 169
+Landroid/app/prediction/AppTargetEvent; 169
+Lorg/xmlpull/v1/XmlPullParserException; 169
+Landroid/app/servertransaction/ObjectPool;.sPoolMap:Ljava/util/Map; 170
+Landroid/app/servertransaction/ClientTransaction; 170
+Landroid/app/servertransaction/StopActivityItem; 170
+Landroid/system/ErrnoException; 171
+Landroid/hardware/location/ContextHubTransaction$OnCompleteListener; 172
+Landroid/app/PendingIntent$OnFinished; 172
+Ljava/lang/NullPointerException; 173
+Landroid/os/strictmode/DiskReadViolation; 174
+Lorg/apache/http/params/HttpParams; 175
+Landroid/nfc/cardemulation/CardEmulation; 176
+Ljava/io/FileDescriptor; 177
+Landroid/content/pm/PackageManager$OnPermissionsChangedListener; 178
+Landroid/security/keystore2/KeyStoreCryptoOperationUtils; 179
+Landroid/app/ActivityTaskManager; 180
+Landroid/util/EventLog; 181
+Ljava/net/URLConnection; 181
+Ljava/net/SocketException; 181
+Ljava/lang/reflect/InvocationTargetException; 181
+Ljava/lang/Enum; 182
+Landroid/widget/AbsListView$SelectionBoundsAdjuster; 183
+Ljava/lang/ClassNotFoundException; 183
+Landroid/content/SyncStatusObserver; 184
+Landroid/content/AsyncTaskLoader$LoadTask; 185
+Landroid/app/LoaderManager$LoaderCallbacks; 185
+Landroid/webkit/CookieSyncManager; 186
+Landroid/webkit/WebViewProvider$ViewDelegate; 187
+Landroid/webkit/WebView; 187
+Landroid/webkit/WebViewProvider$ScrollDelegate; 187
+Landroid/webkit/WebViewProvider; 187
+Landroid/webkit/WebViewFactory;.sTimestamps:Landroid/webkit/WebViewFactory$StartupTimestamps; 188
+Landroid/webkit/WebViewFactoryProvider; 189
+Landroid/webkit/WebViewFactory; 190
+Landroid/os/PowerManager$OnThermalStatusChangedListener; 191
+Landroid/os/Bundle; 192
+Landroid/widget/ProgressBar; 193
+Landroid/graphics/Bitmap$Config;.ALPHA_8:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.RGB_565:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.RGBA_1010102:Landroid/graphics/Bitmap$Config; 194
+Landroid/renderscript/Allocation;.mBitmapOptions:Landroid/graphics/BitmapFactory$Options;.inPreferredConfig:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.RGBA_F16:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.ARGB_4444:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/Bitmap$Config;.HARDWARE:Landroid/graphics/Bitmap$Config; 194
+Landroid/graphics/drawable/StateListDrawable; 195
+Landroid/view/PointerIcon;.gSystemIconsByDisplay:Landroid/util/SparseArray; 196
+Landroid/view/PointerIcon; 196
+Ljavax/net/ssl/SSLServerSocketFactory; 197
+Ljavax/net/ssl/SSLSocketFactory; 198
+Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder; 198
+Ljavax/net/ssl/SSLSessionContext; 199
+Lcom/android/org/bouncycastle/crypto/CryptoServicesRegistrar; 200
+Lsun/security/x509/PKIXExtensions;.KeyUsage_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.PolicyConstraints_Id:Lsun/security/util/ObjectIdentifier; 201
+Ljava/security/cert/PKIXRevocationChecker$Option;.ONLY_END_ENTITY:Ljava/security/cert/PKIXRevocationChecker$Option; 201
+Lsun/security/x509/PKIXExtensions;.ExtendedKeyUsage_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/provider/X509Factory;.certCache:Lsun/security/util/Cache; 201
+Lsun/security/x509/PKIXExtensions;.CertificatePolicies_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.NameConstraints_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.AuthorityKey_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/provider/X509Factory;.certCache:Lsun/security/util/Cache;.cacheMap:Ljava/util/Map; 201
+Ljava/security/cert/PKIXRevocationChecker$Option;.NO_FALLBACK:Ljava/security/cert/PKIXRevocationChecker$Option; 201
+Lsun/security/x509/PKIXExtensions;.SubjectAlternativeName_Id:Lsun/security/util/ObjectIdentifier; 201
+Lsun/security/x509/PKIXExtensions;.PolicyMappings_Id:Lsun/security/util/ObjectIdentifier; 202
+Lsun/security/x509/PKIXExtensions;.InhibitAnyPolicy_Id:Lsun/security/util/ObjectIdentifier; 202
+Lsun/security/x509/PKIXExtensions;.BasicConstraints_Id:Lsun/security/util/ObjectIdentifier; 202
+Ljava/security/Security;.spiMap:Ljava/util/Map; 203
+Lsun/security/x509/X500Name;.commonName_oid:Lsun/security/util/ObjectIdentifier; 204
+Lsun/security/x509/X500Name;.countryName_oid:Lsun/security/util/ObjectIdentifier; 204
+Lsun/security/x509/X500Name;.orgName_oid:Lsun/security/util/ObjectIdentifier; 204
+Ljava/nio/charset/Charset;.cache2:Ljava/util/HashMap; 205
+Ljava/net/URL;.handlers:Ljava/util/Hashtable;.table:[Ljava/util/Hashtable$HashtableEntry; 206
+Ljava/net/URL;.handlers:Ljava/util/Hashtable; 206
+Ljava/net/Inet6AddressImpl;.addressCache:Ljava/net/AddressCache;.cache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap; 207
+Ljava/net/Proxy$Type;.DIRECT:Ljava/net/Proxy$Type; 208
+Ljava/net/ProxySelector;.theProxySelector:Ljava/net/ProxySelector; 208
+Lcom/android/okhttp/okio/SegmentPool; 209
+Lcom/android/okhttp/internal/http/AuthenticatorAdapter;.INSTANCE:Lcom/android/okhttp/Authenticator; 209
+Lcom/android/okhttp/HttpsHandler;.HTTP_1_1_ONLY:Ljava/util/List;.element:Ljava/lang/Object; 209
+Lcom/android/okhttp/ConfigAwareConnectionPool;.instance:Lcom/android/okhttp/ConfigAwareConnectionPool;.networkEventDispatcher:Llibcore/net/event/NetworkEventDispatcher;.listeners:Ljava/util/List; 210
+Lcom/android/okhttp/Dns;.SYSTEM:Lcom/android/okhttp/Dns; 210
+Lcom/android/okhttp/ConfigAwareConnectionPool;.instance:Lcom/android/okhttp/ConfigAwareConnectionPool; 210
+Lcom/android/okhttp/okio/AsyncTimeout; 211
+Ljava/lang/IllegalAccessException; 212
+Ljavax/net/ssl/SSLContext; 213
+Ljavax/net/ssl/HttpsURLConnection; 213
+Ljava/security/Security;.props:Ljava/util/Properties;.map:Ljava/util/concurrent/ConcurrentHashMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.12:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 214
+Ljava/security/Security;.props:Ljava/util/Properties;.map:Ljava/util/concurrent/ConcurrentHashMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.30:Ljava/util/concurrent/ConcurrentHashMap$Node; 214
+Landroid/database/sqlite/SQLiteTransactionListener; 215
+Landroid/accounts/OnAccountsUpdateListener; 216
+Landroid/accounts/AccountManager$20; 217
+Lsun/nio/ch/FileChannelImpl$Unmapper; 218
+Landroid/content/res/Resources;.sResourcesHistory:Ljava/util/Set;.c:Ljava/util/Collection;.m:Ljava/util/Map;.queue:Ljava/lang/ref/ReferenceQueue; 219
+Landroid/text/method/SingleLineTransformationMethod; 220
+Landroid/widget/RelativeLayout; 221
+Landroid/graphics/drawable/BitmapDrawable; 222
+Landroid/graphics/drawable/GradientDrawable; 223
+Landroid/animation/PropertyValuesHolder;.sGetterPropertyMap:Ljava/util/HashMap; 224
+Landroid/animation/PropertyValuesHolder$FloatPropertyValuesHolder;.sJNISetterPropertyMap:Ljava/util/HashMap; 225
+Landroid/graphics/drawable/Drawable;.DEFAULT_TINT_MODE:Landroid/graphics/PorterDuff$Mode; 226
+Landroid/text/StaticLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool; 227
+Landroid/text/StaticLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 227
+Ljava/util/concurrent/ThreadLocalRandom; 228
+Landroid/widget/Space; 229
+Landroid/widget/ScrollView; 230
+Landroid/text/style/LineHeightSpan; 231
+Landroid/text/style/TabStopSpan; 232
+Landroid/text/style/ReplacementSpan; 233
+Landroid/text/style/MetricAffectingSpan; 233
+Landroid/text/style/LeadingMarginSpan; 233
+Landroid/text/style/LineBackgroundSpan; 234
+Landroid/text/style/CharacterStyle; 235
+Landroid/text/style/SuggestionSpan; 236
+Landroid/widget/TextView$ChangeWatcher; 237
+Landroid/text/DynamicLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 238
+Landroid/text/DynamicLayout; 238
+Landroid/text/DynamicLayout$ChangeWatcher; 238
+Landroid/text/style/WrapTogetherSpan; 238
+Landroid/text/DynamicLayout$Builder;.sPool:Landroid/util/Pools$SynchronizedPool; 238
+Landroid/text/method/LinkMovementMethod; 239
+Landroid/text/style/ClickableSpan; 240
+Ljava/util/logging/LogRecord;.globalSequenceNumber:Ljava/util/concurrent/atomic/AtomicLong; 241
+Ljava/lang/Runtime;.currentRuntime:Ljava/lang/Runtime; 242
+Landroid/content/pm/LauncherActivityInfo; 243
+Landroid/database/sqlite/SQLiteMisuseException; 243
+Landroid/speech/tts/TextToSpeech$Connection$SetupConnectionAsyncTask; 243
+Landroid/database/sqlite/SQLiteCantOpenDatabaseException; 243
+Landroid/database/sqlite/SQLiteDatabaseCorruptException; 243
+Landroid/database/sqlite/SQLiteDatabaseLockedException; 243
+Ljava/util/Map$Entry; 243
+Ljava/util/zip/ZipException; 243
+Landroid/database/sqlite/SQLiteAccessPermException; 243
+Landroid/speech/tts/TextToSpeech$OnInitListener; 243
+Landroid/app/Notification$MessagingStyle; 244
+Landroid/text/TextUtils$TruncateAt; 245
+Landroid/app/smartspace/SmartspaceTarget; 246
+Landroid/app/prediction/AppTarget; 246
+Landroid/app/smartspace/uitemplatedata/BaseTemplateData; 246
+Landroid/location/LocationManager;.sLocationListeners:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry; 247
+Landroid/location/LocationManager;.sLocationListeners:Ljava/util/WeakHashMap; 247
+Landroid/service/notification/ConditionProviderService; 248
+Landroid/os/WorkSource; 249
+Landroid/security/keystore2/AndroidKeyStoreProvider; 249
+Ljava/net/Socket; 249
+Lcom/android/internal/listeners/ListenerTransport; 249
+Landroid/os/ParcelUuid; 250
+Landroid/telephony/emergency/EmergencyNumber; 251
+Lcom/android/internal/telephony/uicc/UiccProfile$4; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$IncomingSms; 251
+Lcom/android/internal/telephony/SmsStorageMonitor$1; 251
+Lcom/android/internal/telephony/TelephonyDevController; 251
+Lcom/android/internal/telephony/uicc/UiccController; 251
+Lcom/android/internal/telephony/emergency/EmergencyNumberTracker$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$DataCallSession; 251
+Lcom/android/internal/telephony/TelephonyDevController;.mSims:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsAcsProvisioningStats; 251
+Ljava/lang/UnsupportedOperationException; 251
+Landroid/database/CursorToBulkCursorAdaptor; 251
+Lcom/android/internal/telephony/satellite/PointingAppController; 251
+Landroid/telephony/ModemActivityInfo; 251
+Lcom/android/internal/telephony/imsphone/ImsPhone; 251
+Lcom/android/internal/telephony/ServiceStateTracker; 251
+Lcom/android/internal/telephony/IccSmsInterfaceManager; 251
+Lcom/android/internal/telephony/util/NotificationChannelController$1; 251
+Lcom/android/internal/telephony/RilWakelockInfo; 251
+Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler$GsmCbTestBroadcastReceiver; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportFeatureTagStats; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$UceEventStats; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$BindingState; 251
+Lcom/android/internal/telephony/ims/ImsResolver$3; 251
+Landroid/net/NetworkPolicyManager$SubscriptionCallbackProxy; 251
+Lcom/android/internal/telephony/TelephonyDevController;.mModems:Ljava/util/ArrayList; 251
+Landroid/telephony/ims/aidl/IImsServiceController$Stub$Proxy; 251
+Lcom/android/internal/telephony/CarrierPrivilegesTracker$1; 251
+Lcom/android/internal/telephony/CommandException; 251
+Lcom/android/ims/FeatureConnector$1; 251
+Lcom/android/internal/telephony/IWapPushManager; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipDelegateStats; 251
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mTtyModeReceivedRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mClassLoader:Ljava/lang/ClassLoader; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mMmiCompleteRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/i18n/timezone/TelephonyLookup; 251
+Landroid/telephony/BarringInfo$BarringServiceInfo; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequests; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$ConnectedState$14; 251
+Lcom/android/internal/telephony/SmsBroadcastUndelivered; 251
+Lcom/android/internal/telephony/LocaleTracker; 251
+Lcom/android/internal/telephony/PhoneSubInfoController; 251
+Lcom/android/internal/telephony/CarrierKeyDownloadManager$1; 251
+Lcom/android/internal/telephony/GsmCdmaCallTracker$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.339:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/ServiceStateTracker$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.353:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/euicc/EuiccCardController$SimSlotStatusChangedBroadcastReceiver; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$PresenceNotifyEvent; 251
+Lcom/android/internal/telephony/SimActivationTracker$1; 251
+Landroid/telephony/ModemInfo; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1393:[Ljava/lang/String; 251
+Landroid/telephony/CellSignalStrengthWcdma; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteProvision; 251
+Lcom/android/internal/telephony/PhoneConfigurationManager; 251
+Lcom/android/internal/telephony/SmsApplication$SmsPackageMonitor; 251
+Landroid/telephony/TelephonyRegistryManager$3; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallSession; 251
+Landroid/os/Handler$MessengerImpl; 251
+Lcom/android/internal/telephony/LocaleTracker$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularDataServiceSwitch; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mInCallVoicePrivacyOffRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSosMessageRecommender; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationServiceDescStats; 251
+Lcom/android/internal/telephony/uicc/UiccPkcs15$Pkcs15Selector; 251
+Lcom/android/internal/telephony/CarrierResolver$2; 251
+Lcom/android/internal/telephony/CarrierActionAgent$1; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mPhones:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/SmsController; 251
+Lcom/android/internal/telephony/uicc/euicc/EuiccCardException; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationTermination; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1125:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/NetworkTypeController$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.803:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/uicc/asn1/TagNotFoundException; 251
+Lcom/android/internal/telephony/CarrierServiceBindHelper$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CellularServiceState; 251
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager; 251
+Lcom/android/internal/telephony/InboundSmsHandler$NewMessageNotificationActionReceiver; 251
+Lcom/android/internal/telephony/CarrierActionAgent; 251
+Lcom/android/i18n/timezone/TimeZoneFinder; 251
+Lcom/android/internal/telephony/RILRequest; 251
+Lcom/android/internal/telephony/RIL;.sRilTimeHistograms:Landroid/util/SparseArray; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.33:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/MccTable; 251
+Lcom/android/internal/telephony/uicc/UiccProfile$2; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$CarrierIdMismatch; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1235:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules; 251
+Landroid/telephony/CellSignalStrengthTdscdma; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerListenerEvent; 251
+Lcom/android/internal/telephony/SmsDispatchersController; 251
+Landroid/timezone/TelephonyLookup; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteOutgoingDatagram; 251
+Lcom/android/internal/telephony/SMSDispatcher$1; 251
+Lcom/android/internal/telephony/AppSmsManager; 251
+Landroid/timezone/TimeZoneFinder; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mBackgroundCalls:Ljava/util/ArrayList; 251
+Lcom/android/ims/rcs/uce/eab/EabProvider; 251
+Lcom/android/internal/telephony/uicc/PinStorage$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsDedicatedBearerEvent; 251
+Landroid/telephony/CellSignalStrengthLte; 251
+Landroid/telephony/ims/ProvisioningManager$Callback$CallbackBinder; 251
+Lcom/android/ims/ImsManager;.IMS_STATS_CALLBACKS:Landroid/util/SparseArray;.mKeys:[I 251
+Landroid/telephony/CellSignalStrengthNr; 251
+Lcom/android/internal/telephony/SomeArgs; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mInCallVoicePrivacyOnRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/StateMachine$SmHandler; 251
+Lcom/android/internal/telephony/PackageChangeReceiver; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingShortCodeSms; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$NetworkRequestsV2; 251
+Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$AvailableState; 251
+Lcom/android/ims/internal/IImsServiceFeatureCallback$Stub$Proxy; 251
+Landroid/telephony/data/ApnSetting;.APN_TYPE_INT_MAP:Ljava/util/Map; 251
+Lcom/android/internal/telephony/RadioInterfaceCapabilityController; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationStats; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$VoiceCallRatUsage; 251
+Lcom/android/internal/telephony/metrics/TelephonyMetrics; 251
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall; 251
+Lcom/android/internal/telephony/NetworkRegistrationManager$NetworkRegStateCallback; 251
+Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$ConnectedState; 251
+Lcom/android/internal/telephony/RadioConfig; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$DisconnectedState; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteSession; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mDisplayInfoRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo; 251
+Lcom/android/internal/telephony/GsmCdmaPhone; 251
+Lcom/android/internal/telephony/TelephonyTester$1; 251
+Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler$CdmaScpTestBroadcastReceiver; 251
+Lcom/android/internal/telephony/NetworkTypeController$DefaultState; 251
+Landroid/net/TelephonyNetworkSpecifier; 251
+Lcom/android/internal/telephony/NitzStateMachine; 251
+Landroid/app/timezonedetector/TimeZoneDetector; 251
+Lcom/android/internal/telephony/IntentBroadcaster$1; 251
+Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher; 251
+Lcom/android/internal/telephony/ims/ImsResolver$1; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$OutgoingSms; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$UnmeteredNetworks; 251
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mClassLoader:Ljava/lang/ClassLoader;.packages:Ljava/util/Map;.m:Ljava/util/Map; 251
+Lcom/android/internal/telephony/euicc/EuiccController; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mForegroundCalls:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/satellite/SatelliteModemInterface; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.531:[Ljava/lang/String; 251
+Lcom/android/ims/ImsManager;.IMS_STATS_CALLBACKS:Landroid/util/SparseArray; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$1; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.467:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipMessageResponse; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SipTransportSession; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$UnavailableState; 251
+Lcom/android/internal/telephony/DeviceStateMonitor$3; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mSignalInfoRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/ims/ImsManager;.IMS_STATS_CALLBACKS:Landroid/util/SparseArray;.mValues:[Ljava/lang/Object; 251
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager; 251
+Lcom/android/internal/telephony/DisplayInfoController; 251
+Lcom/android/internal/telephony/ims/ImsResolver$2; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.1377:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyServiceState$NetworkRegistrationInfo; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteController; 251
+Landroid/telephony/ims/RegistrationManager$RegistrationCallback$RegistrationBinder; 251
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$EmergencyNumbersInfo; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$GbaEvent; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.23:[Ljava/lang/String; 251
+Landroid/telephony/CellSignalStrengthCdma; 251
+Landroid/telephony/TelephonyLocalConnection; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$SatelliteIncomingDatagram; 251
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker$2; 251
+Lcom/android/internal/telephony/ims/ImsResolver; 251
+Lcom/android/internal/telephony/SmsStorageMonitor; 251
+Lcom/android/internal/telephony/uicc/UiccProfile; 251
+Landroid/telephony/ims/ImsMmTelManager$CapabilityCallback$CapabilityBinder; 251
+Lcom/android/internal/telephony/euicc/EuiccCardController; 251
+Lcom/android/internal/telephony/SmsBroadcastUndelivered$1; 251
+Lcom/android/internal/telephony/GsmCdmaCallTracker; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$RcsClientProvisioningStats; 251
+Lcom/android/internal/telephony/cat/CatService; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.761:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/SmsApplication; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mDisconnectRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/PhoneFactory; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mHandlerMap:Ljava/util/HashMap; 251
+Landroid/os/AsyncResult; 251
+Lcom/android/internal/telephony/ProxyController; 251
+Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler$CdmaCbTestBroadcastReceiver; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.453:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/MultiSimSettingController; 251
+Ljava/io/BufferedReader; 251
+Landroid/telephony/CellSignalStrengthGsm; 251
+Lcom/android/internal/telephony/SimActivationTracker; 251
+Lcom/android/internal/telephony/CellBroadcastServiceManager; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mRingingCalls:Ljava/util/ArrayList; 251
+Lcom/android/internal/telephony/IntentBroadcaster; 251
+Lcom/android/internal/telephony/nano/PersistAtomsProto$ImsRegistrationFeatureTagStats; 251
+Lcom/android/internal/telephony/euicc/EuiccConnector$EuiccPackageMonitor; 251
+Lcom/android/internal/telephony/CallManager;.INSTANCE:Lcom/android/internal/telephony/CallManager;.mSuppServiceFailedRegistrants:Lcom/android/internal/telephony/RegistrantList;.registrants:Ljava/util/ArrayList; 251
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mClassLoader:Ljava/lang/ClassLoader;.packages:Ljava/util/Map;.m:Ljava/util/Map;.table:[Ljava/util/HashMap$Node; 251
+Lcom/android/internal/telephony/CarrierServiceBindHelper$CarrierServicePackageMonitor; 251
+Lcom/android/internal/telephony/TelephonyComponentFactory; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.637:[Ljava/lang/String; 251
+Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo; 251
+Landroid/telephony/CarrierConfigManager;.sDefaults:Landroid/os/PersistableBundle;.mMap:Landroid/util/ArrayMap;.mArray:[Ljava/lang/Object;.651:[Ljava/lang/String; 251
+Lcom/android/internal/telephony/SmsUsageMonitor; 251
+Lcom/android/internal/telephony/CommandException$Error;.INVALID_SIM_STATE:Lcom/android/internal/telephony/CommandException$Error; 251
+Landroid/hardware/display/DisplayManagerGlobal$DisplayManagerCallback; 252
+Landroid/app/ActivityThread$ApplicationThread; 252
+Landroid/app/ActivityManager$MyUidObserver; 253
+Landroid/media/browse/MediaBrowser$ServiceCallbacks; 253
+Landroid/media/session/MediaController$CallbackStub; 253
+Landroid/media/session/MediaSessionManager$OnMediaKeyEventSessionChangedListener; 253
+Landroid/app/PendingIntent$CancelListener; 253
+Landroid/media/AudioManager$2; 253
+Landroid/database/ContentObserver$Transport; 253
+Landroid/media/session/MediaSessionManager$SessionsChangedWrapper$1; 253
+Landroid/content/ContentProvider$PipeDataWriter; 254
+Landroid/security/net/config/UserCertificateSource$NoPreloadHolder; 255
+Landroid/view/Window$Callback; 256
+Landroid/transition/TransitionManager;.sDefaultTransition:Landroid/transition/Transition;.mTransitions:Ljava/util/ArrayList;.elementData:[Ljava/lang/Object;.1:Landroid/transition/ChangeBounds;.mCurrentAnimators:Ljava/util/ArrayList; 256
+Landroid/transition/TransitionManager;.sDefaultTransition:Landroid/transition/Transition;.mTransitions:Ljava/util/ArrayList;.elementData:[Ljava/lang/Object;.2:Landroid/transition/Fade;.mCurrentAnimators:Ljava/util/ArrayList; 256
+Landroid/transition/TransitionManager;.sPendingTransitions:Ljava/util/ArrayList; 256
+Landroid/transition/TransitionManager;.sDefaultTransition:Landroid/transition/Transition;.mTransitions:Ljava/util/ArrayList;.elementData:[Ljava/lang/Object;.0:Landroid/transition/Fade;.mCurrentAnimators:Ljava/util/ArrayList; 256
+Landroid/view/AttachedSurfaceControl$OnBufferTransformHintChangedListener; 257
+Landroid/webkit/ValueCallback; 258
+Landroid/webkit/WebResourceRequest; 258
+Landroid/webkit/WebChromeClient$CustomViewCallback; 258
+Landroid/hardware/camera2/CameraCharacteristics;.INFO_SUPPORTED_HARDWARE_LEVEL:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 258
+Landroid/accounts/Account; 258
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 258
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/params/StreamConfigurationDuration; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.HEIC_AVAILABLE_HEIC_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/params/HighSpeedVideoConfiguration; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/CameraCharacteristics;.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+I 259
+Landroid/hardware/camera2/CameraCharacteristics;.REQUEST_AVAILABLE_CAPABILITIES:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 259
+Landroid/hardware/camera2/params/StreamConfiguration; 259
+Z 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_PIXEL_ARRAY_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_FOCAL_LENGTH:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_INFO_AVAILABLE_APERTURES:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.DISTORTION_CORRECTION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.EXTENSION_STRENGTH:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+J 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_PHYSICAL_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.TONEMAP_PRESET_CURVE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+B 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AF_TRIGGER:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_EXPOSURE_COMPENSATION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[D 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AWB_REGIONS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.REQUEST_AVAILABLE_SESSION_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_EXPOSURE_TIME:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_CALIBRATION_TRANSFORM2:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_TRANSFORM:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/content/res/Resources$Theme; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_LOCK:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+F 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_FILTER_DENSITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_OPTICAL_STABILIZATION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.NOISE_REDUCTION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_FRAME_DURATION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_REGIONS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_EXTENDED_SCENE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_OIS_DATA_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_TEST_PATTERN_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.HOT_PIXEL_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_ANTIBANDING_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_LENS_SHADING_MAP_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SCALER_CROP_REGION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_FOCUS_DISTANCE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.TONEMAP_GAMMA:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_REFERENCE_ILLUMINANT2:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_REFERENCE_ILLUMINANT1:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[F 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_ZOOM_RATIO:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_ABERRATION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.TONEMAP_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.REQUEST_AVAILABLE_REQUEST_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SCALER_ROTATE_AND_CROP:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_GAINS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_COLOR_TRANSFORM1:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AF_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_SENSITIVITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_INFO_AVAILABLE_FOCAL_LENGTHS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_OPTICAL_BLACK_REGIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_QUALITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.FLASH_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_POST_RAW_SENSITIVITY_BOOST:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_WHITE_LEVEL:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_SETTINGS_OVERRIDE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[Landroid/hardware/camera2/params/MeteringRectangle; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AWB_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.LOGICAL_MULTI_CAMERA_PHYSICAL_IDS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_INFO_EXPOSURE_TIME_RANGE:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/lang/Float; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_ENABLE_ZSL:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.INFO_DEVICE_STATE_ORIENTATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_CALIBRATION_TRANSFORM1:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.EDGE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_CAPTURE_INTENT:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_ORIENTATION:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_ORIENTATION:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CameraCharacteristics;.SENSOR_COLOR_TRANSFORM2:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[J 260
+Landroid/hardware/camera2/CameraCharacteristics;.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/util/concurrent/Phaser; 260
+Landroid/hardware/camera2/CaptureRequest;.BLACK_LEVEL_LOCK:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.COLOR_CORRECTION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_SCENE_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_THUMBNAIL_SIZE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SHADING_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_FACE_DETECT_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.STATISTICS_HOT_PIXEL_MAP_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AUTOFRAMING:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_TARGET_FPS_RANGE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AWB_LOCK:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_TEST_PATTERN_DATA:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AE_PRECAPTURE_TRIGGER:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.FLASH_STRENGTH_LEVEL:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_VIDEO_STABILIZATION_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/lang/Boolean; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_EFFECT_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.LENS_APERTURE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.JPEG_THUMBNAIL_QUALITY:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Landroid/hardware/camera2/CaptureRequest;.CONTROL_AF_REGIONS:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+Ljava/lang/Long; 260
+Landroid/hardware/camera2/CaptureRequest;.SENSOR_PIXEL_MODE:Landroid/hardware/camera2/CaptureRequest$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 260
+[Ljava/lang/String; 261
+[Z 262
+Ljava/lang/Class$Caches;.genericInterfaces:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap; 263
+Ljava/util/Map; 264
+Ljava/nio/Bits; 265
+Ljava/nio/DirectByteBuffer; 266
+Ljava/io/File; 267
+Ljava/nio/ByteBuffer; 268
+Ljava/io/InputStream; 269
+Landroid/os/ParcelFileDescriptor; 270
+Landroid/os/BinderProxy;.sProxyMap:Landroid/os/BinderProxy$ProxyMap; 271
+Landroid/app/PendingIntent; 272
+Landroid/content/Intent; 273
+Landroid/net/Uri$HierarchicalUri; 274
+Landroid/net/Uri$StringUri; 275
+Landroid/net/Uri$PathPart;.EMPTY:Landroid/net/Uri$PathPart; 276
+Lcom/android/internal/telephony/MccTable;.FALLBACKS:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.6:Ljava/util/HashMap$Node;.key:Ljava/lang/Object; 277
+Landroid/icu/text/DecimalFormatSymbols;.cachedLocaleData:Landroid/icu/impl/CacheBase;.map:Ljava/util/concurrent/ConcurrentHashMap; 278
+Llibcore/icu/DecimalFormatData;.CACHE:Ljava/util/concurrent/ConcurrentHashMap; 279
+Landroid/icu/impl/CurrencyData;.provider:Landroid/icu/impl/CurrencyData$CurrencyDisplayInfoProvider; 280
+Lcom/android/internal/infra/AndroidFuture; 281
+Lcom/android/internal/util/LatencyTracker$Action; 282
+Landroid/app/AppOpsManager$Mode; 283
+Landroid/view/accessibility/AccessibilityManager$AccessibilityServicesStateChangeListener; 284
+Landroid/annotation/IdRes; 285
+Landroid/content/pm/PackageItemInfo; 286
+Ljava/util/Random; 287
+Landroid/widget/RadioButton; 288
+Lcom/android/internal/policy/PhoneWindow$PanelFeatureState$SavedState; 289
+Landroid/graphics/Insets; 290
+Landroid/view/View;.sNextGeneratedId:Ljava/util/concurrent/atomic/AtomicInteger; 291
+Landroid/graphics/drawable/LayerDrawable; 292
+Landroid/animation/LayoutTransition; 293
+Llibcore/reflect/AnnotationFactory;.cache:Ljava/util/Map; 294
+Llibcore/reflect/AnnotationFactory;.cache:Ljava/util/Map;.table:[Ljava/util/WeakHashMap$Entry; 294
+Ljava/lang/reflect/Proxy;.proxyClassCache:Ljava/lang/reflect/WeakCache;.reverseMap:Ljava/util/concurrent/ConcurrentMap; 295
+Ljava/lang/reflect/Proxy$ProxyClassFactory;.nextUniqueNumber:Ljava/util/concurrent/atomic/AtomicLong; 295
+Ljava/lang/reflect/Proxy;.proxyClassCache:Ljava/lang/reflect/WeakCache;.map:Ljava/util/concurrent/ConcurrentMap; 296
+Ljava/lang/Object; 297
+Ljava/lang/invoke/MethodType;.internTable:Ljava/lang/invoke/MethodType$ConcurrentWeakInternSet;.map:Ljava/util/concurrent/ConcurrentMap; 298
+Ljava/nio/channels/SocketChannel;.dexCache:Ljava/lang/Object; 298
+Ljava/lang/invoke/MethodType;.objectOnlyTypes:[Ljava/lang/invoke/MethodType; 299
+Ljava/util/concurrent/ForkJoinTask; 300
+Ljava/util/concurrent/CompletableFuture; 301
+Landroid/app/Notification$BigTextStyle; 302
+Landroid/content/pm/ApplicationInfo; 303
+Ljava/security/Signature;.signatureInfo:Ljava/util/Map;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.13:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 304
+Lsun/security/x509/X500Name;.stateName_oid:Lsun/security/util/ObjectIdentifier; 305
+Lsun/security/x509/X500Name;.localityName_oid:Lsun/security/util/ObjectIdentifier; 306
+Lsun/security/x509/X500Name;.orgUnitName_oid:Lsun/security/util/ObjectIdentifier; 306
+Ljava/util/UUID; 307
+Landroid/app/slice/Slice; 308
+Ljava/util/Locale;.FRENCH:Ljava/util/Locale; 308
+Landroid/os/NullVibrator; 308
+Ldalvik/system/CloseGuard;.MESSAGE:Ljava/lang/String; 308
+Lsun/util/locale/BaseLocale$Cache;.CACHE:Lsun/util/locale/BaseLocale$Cache;.map:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.22:Ljava/util/concurrent/ConcurrentHashMap$Node;.val:Ljava/lang/Object;.referent:Ljava/lang/Object; 308
+Ljava/util/Locale$Cache;.LOCALECACHE:Ljava/util/Locale$Cache;.map:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.24:Ljava/util/concurrent/ConcurrentHashMap$Node;.val:Ljava/lang/Object;.referent:Ljava/lang/Object; 308
+Landroid/app/Activity$$ExternalSyntheticLambda0; 308
+Landroid/icu/impl/locale/BaseLocale;.CACHE:Landroid/icu/impl/locale/BaseLocale$Cache;._map:Ljava/util/concurrent/ConcurrentHashMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.0:Ljava/util/concurrent/ConcurrentHashMap$Node; 308
+Ljava/util/Locale;.ITALIAN:Ljava/util/Locale; 308
+Landroid/media/MediaRouter2Manager$Callback; 308
+Lsun/util/locale/BaseLocale$Cache;.CACHE:Lsun/util/locale/BaseLocale$Cache;.map:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.29:Ljava/util/concurrent/ConcurrentHashMap$Node;.val:Ljava/lang/Object;.referent:Ljava/lang/Object; 308
+Ljava/util/Locale;.GERMAN:Ljava/util/Locale; 309
+Landroid/icu/impl/StandardPlural; 310
+Landroid/icu/impl/number/range/StandardPluralRanges; 311
+Landroid/icu/impl/PluralRulesLoader;.loader:Landroid/icu/impl/PluralRulesLoader; 311
+Landroid/icu/impl/PluralRulesLoader;.loader:Landroid/icu/impl/PluralRulesLoader;.pluralRulesCache:Ljava/util/Map; 311
+Landroid/icu/text/PluralRules$Operand; 311
+Landroid/icu/util/Calendar;.PATTERN_CACHE:Landroid/icu/impl/ICUCache; 312
+Landroid/icu/impl/DateNumberFormat;.CACHE:Landroid/icu/impl/SimpleCache; 313
+Landroid/text/format/DateFormat; 314
+Landroid/view/View$OnDragListener; 315
+Landroid/hardware/input/InputManager$InputDeviceListener; 316
+Landroid/hardware/input/InputManagerGlobal; 317
+Landroid/hardware/SystemSensorManager; 318
+Lcom/android/internal/os/BackgroundThread; 319
+Ljava/lang/Throwable; 320
+Landroid/app/NotificationManager; 321
+Landroid/app/NotificationChannel; 322
+Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener; 323
+Landroid/content/pm/VersionedPackage; 324
+Landroid/app/AppOpsManager; 325
+Ldalvik/system/ZipPathValidator; 326
+Landroid/content/pm/PackageManager;.sPackageInfoCache:Landroid/app/PropertyInvalidatedCache;.mSkips:[J 327
+Landroid/content/pm/PackageManager;.sApplicationInfoCache:Landroid/app/PropertyInvalidatedCache;.mSkips:[J 328
+Lsun/util/locale/BaseLocale$Cache;.CACHE:Lsun/util/locale/BaseLocale$Cache;.map:Ljava/util/concurrent/ConcurrentMap; 329
+Landroid/content/Context; 330
+Ljava/util/concurrent/Executor; 331
+Ljava/util/concurrent/ScheduledExecutorService; 332
+Ljava/util/concurrent/ExecutorService; 332
+Landroid/view/Window$OnFrameMetricsAvailableListener; 333
+Ljava/lang/annotation/Annotation; 334
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 335
+Ljava/util/concurrent/CancellationException; 336
+Ljava/lang/NoSuchMethodException; 337
+Landroid/os/strictmode/CustomViolation; 338
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.3:Ljava/util/WeakHashMap$Entry; 339
+Lcom/android/internal/policy/PhoneWindow; 340
+Landroid/view/autofill/AutofillValue; 340
+Landroid/widget/TextView$SavedState; 341
+Landroid/text/method/MetaKeyKeyListener;.SYM:Ljava/lang/Object; 342
+Landroid/text/method/MetaKeyKeyListener;.ALT:Ljava/lang/Object; 342
+Landroid/text/method/MetaKeyKeyListener;.SELECTING:Ljava/lang/Object; 342
+Landroid/text/method/MetaKeyKeyListener;.CAP:Ljava/lang/Object; 342
+Landroid/widget/PopupWindow$PopupBackgroundView; 343
+Landroid/widget/TextView;.TEMP_RECTF:Landroid/graphics/RectF; 343
+Landroid/text/method/ScrollingMovementMethod; 343
+Landroid/icu/impl/locale/UnicodeLocaleExtension;.EMPTY_SORTED_SET:Ljava/util/SortedSet;.m:Ljava/util/NavigableMap; 343
+Landroid/widget/PopupWindow$PopupDecorView; 343
+Landroid/widget/Editor$TextRenderNode; 343
+Landroid/widget/Editor$PositionListener; 344
+Landroid/text/style/SpellCheckSpan; 345
+Landroid/text/method/ArrowKeyMovementMethod; 346
+Landroid/text/method/TextKeyListener;.sInstance:[Landroid/text/method/TextKeyListener; 346
+Landroid/text/TextUtils$TruncateAt;.MARQUEE:Landroid/text/TextUtils$TruncateAt; 347
+Landroid/view/autofill/Helper; 348
+Lcom/android/internal/util/LatencyTracker; 349
+Lcom/android/internal/util/LatencyTracker$SLatencyTrackerHolder; 349
+Landroid/graphics/drawable/Icon; 350
+Landroid/text/style/AlignmentSpan; 351
+Landroid/text/MeasuredParagraph;.sPool:Landroid/util/Pools$SynchronizedPool;.mPool:[Ljava/lang/Object; 352
+Landroid/text/MeasuredParagraph;.sPool:Landroid/util/Pools$SynchronizedPool; 352
+Landroid/icu/impl/ICUResourceBundleReader;.CACHE:Landroid/icu/impl/ICUResourceBundleReader$ReaderCache;.map:Ljava/util/concurrent/ConcurrentHashMap; 353
+Landroid/location/ILocationManager$Stub;.dexCache:Ljava/lang/Object; 354
+Landroid/annotation/CurrentTimeMillisLong; 355
+Ljava/lang/reflect/Method; 356
+Lcom/android/internal/os/ZygoteInit; 356
+Landroid/database/DatabaseUtils; 356
+Landroid/os/HandlerThread; 356
+Ljava/security/Signature;.signatureInfo:Ljava/util/Map;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 357
+Ljava/security/Signature;.signatureInfo:Ljava/util/Map; 358
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.queue:Ljava/lang/ref/ReferenceQueue; 359
+Landroid/telephony/TelephonyRegistryManager; 360
+Landroid/graphics/HardwareRenderer; 361
+Landroid/os/BinderProxy; 362
+Landroid/app/compat/CompatChanges;.QUERY_CACHE:Landroid/app/compat/ChangeIdStateCache;.mCache:Ljava/util/LinkedHashMap; 363
+Landroid/app/compat/CompatChanges;.QUERY_CACHE:Landroid/app/compat/ChangeIdStateCache; 363
+Landroid/app/AlarmManager; 364
+Landroid/net/metrics/DhcpClientEvent; 365
+[I 366
+Landroid/media/MediaCodecList; 367
+Landroid/graphics/drawable/InsetDrawable; 368
+Landroid/widget/ProgressBar$SavedState; 369
+Landroid/widget/ScrollView$SavedState; 370
+Landroid/graphics/drawable/AnimatedVectorDrawable; 371
+Landroid/widget/ListView; 372
+Landroid/widget/AbsListView; 373
+Landroid/widget/AbsListView$SavedState; 373
+Landroid/widget/CompoundButton$SavedState; 374
+Landroid/widget/HorizontalScrollView$SavedState; 375
+Landroid/widget/HorizontalScrollView; 376
+Landroid/icu/text/MeasureFormat;.hmsTo012:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.1:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 377
+Landroid/icu/text/MeasureFormat;.hmsTo012:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.6:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 377
+Landroid/view/View$OnSystemUiVisibilityChangeListener; 378
+Ljava/util/AbstractMap; 379
+Landroid/telephony/euicc/EuiccCardManager$ResultCallback; 380
+Ljava/lang/Character$UnicodeBlock;.CJK_SYMBOLS_AND_PUNCTUATION:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KANBUN:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HANGUL_COMPATIBILITY_JAMO:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KATAKANA:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HANGUL_SYLLABLES:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.ENCLOSED_CJK_LETTERS_AND_MONTHS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HANGUL_JAMO:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.BOPOMOFO_EXTENDED:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY_FORMS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.BOPOMOFO:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HIRAGANA:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.HALFWIDTH_AND_FULLWIDTH_FORMS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KANGXI_RADICALS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_RADICALS_SUPPLEMENT:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.KATAKANA_PHONETIC_EXTENSIONS:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY:Ljava/lang/Character$UnicodeBlock; 381
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_COMPATIBILITY_IDEOGRAPHS:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_UNIFIED_IDEOGRAPHS:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:Ljava/lang/Character$UnicodeBlock; 382
+Ljava/lang/Character$UnicodeBlock;.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:Ljava/lang/Character$UnicodeBlock; 382
+Lcom/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry; 383
+Landroid/view/Window$DecorCallback; 383
+Landroid/view/inputmethod/EditorInfo; 383
+Landroid/view/MenuItem$OnActionExpandListener; 384
+Ljava/util/Locale;.JAPANESE:Ljava/util/Locale; 385
+Ljava/util/Locale;.KOREAN:Ljava/util/Locale; 385
+Lcom/android/internal/config/appcloning/AppCloningDeviceConfigHelper; 386
+Landroid/telecom/PhoneAccountHandle; 387
+Landroid/content/AsyncQueryHandler; 388
+Landroid/speech/RecognitionListener; 389
+Ljava/lang/InstantiationException; 390
+Ljava/util/concurrent/ExecutionException; 391
+Landroid/icu/text/DateIntervalInfo;.DIICACHE:Landroid/icu/impl/ICUCache; 392
+Landroid/text/format/DateIntervalFormat;.CACHED_FORMATTERS:Landroid/util/LruCache;.map:Ljava/util/LinkedHashMap; 392
+Landroid/icu/text/DateIntervalFormat;.LOCAL_PATTERN_CACHE:Landroid/icu/impl/ICUCache; 392
+Landroid/icu/impl/OlsonTimeZone; 392
+Landroid/text/format/DateIntervalFormat;.CACHED_FORMATTERS:Landroid/util/LruCache; 392
+Landroid/graphics/drawable/Drawable; 393
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 394
+Landroid/app/Activity; 395
+Landroid/icu/text/PluralRules$KeywordStatus;.INVALID:Landroid/icu/text/PluralRules$KeywordStatus;.name:Ljava/lang/String; 396
+Landroid/net/Uri; 396
+Lsun/util/calendar/CalendarSystem;.calendars:Ljava/util/concurrent/ConcurrentMap; 396
+Landroid/animation/PropertyValuesHolder$IntPropertyValuesHolder;.sJNISetterPropertyMap:Ljava/util/HashMap; 397
+Landroid/graphics/drawable/ShapeDrawable; 398
+Lcom/android/internal/widget/ActionBarContextView; 399
+Landroid/widget/Toolbar$SavedState; 399
+Lcom/android/internal/widget/ActionBarContainer; 399
+Lcom/android/internal/widget/ActionBarOverlayLayout; 399
+Lcom/android/internal/widget/ActionBarContainer$ActionBarBackgroundDrawable; 399
+Landroid/widget/ActionMenuPresenter$OverflowMenuButton; 400
+Landroid/widget/ActionMenuView; 401
+Landroid/content/res/Configuration; 402
+Ljava/util/IdentityHashMap;.NULL_KEY:Ljava/lang/Object; 403
+Ljava/util/concurrent/ForkJoinPool; 404
+Landroid/os/ResultReceiver; 405
+Ljava/util/concurrent/TimeoutException; 406
+Ljava/io/IOException; 407
+Landroid/accounts/AccountAuthenticatorResponse; 408
+Landroid/nfc/NfcAdapter; 409
+Landroid/nfc/NfcAdapter;.sNfcAdapters:Ljava/util/HashMap; 409
+Landroid/app/backup/BackupManager; 410
+Landroid/app/NotificationChannelGroup; 411
+Landroid/content/pm/ParceledListSlice; 411
+Landroid/os/FileObserver; 412
+Landroid/os/UserHandle; 413
+Landroid/content/pm/PackageManager$NameNotFoundException; 414
+[Ljava/lang/Integer; 415
+Landroid/animation/PropertyValuesHolder;.sSetterPropertyMap:Ljava/util/HashMap; 415
+Landroid/content/LocusId; 416
+Landroid/view/contentcapture/ContentCaptureContext; 416
+Landroid/telephony/ims/RegistrationManager;.IMS_REG_TO_ACCESS_TYPE_MAP:Ljava/util/Map;.table:[Ljava/lang/Object;.18:Ljava/lang/Integer; 417
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.4:Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.2:Ljava/util/concurrent/ConcurrentHashMap$Node;.next:Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/internal/telephony/cdnr/CarrierDisplayNameResolver;.EF_SOURCE_PRIORITY:Ljava/util/List;.a:[Ljava/lang/Object;.9:Ljava/lang/Integer; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap;.table:[Ljava/util/concurrent/ConcurrentHashMap$Node;.56:Ljava/util/concurrent/ConcurrentHashMap$Node; 418
+Lcom/android/internal/telephony/cdnr/CarrierDisplayNameResolver;.EF_SOURCE_PRIORITY:Ljava/util/List;.a:[Ljava/lang/Object;.5:Ljava/lang/Integer; 418
+Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;.pool:Ljava/util/concurrent/ConcurrentMap; 418
+Landroid/widget/EditText; 419
+Landroid/widget/CheckedTextView; 420
+Landroid/os/strictmode/UnsafeIntentLaunchViolation; 421
+Landroid/app/Service; 422
+Ldalvik/system/BlockGuard; 423
+Landroid/hardware/devicestate/DeviceStateManagerGlobal; 424
+Landroid/hardware/camera2/CameraCharacteristics;.SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 425
+Landroid/hardware/camera2/marshal/MarshalRegistry;.sMarshalerMap:Ljava/util/HashMap; 425
+Landroid/hardware/camera2/CameraCharacteristics;.LENS_FACING:Landroid/hardware/camera2/CameraCharacteristics$Key;.mKey:Landroid/hardware/camera2/impl/CameraMetadataNative$Key; 425
+Landroid/content/ClipboardManager$OnPrimaryClipChangedListener; 426
+Landroid/icu/text/BreakIterator;.iterCache:[Landroid/icu/impl/CacheValue; 427
+Landroid/app/PropertyInvalidatedCache;.sCaches:Ljava/util/WeakHashMap;.table:[Ljava/util/WeakHashMap$Entry;.13:Ljava/util/WeakHashMap$Entry; 428
+Landroid/icu/text/Collator; 429
+Landroid/icu/impl/number/parse/NanMatcher;.DEFAULT:Landroid/icu/impl/number/parse/NanMatcher;.uniSet:Landroid/icu/text/UnicodeSet;.strings:Ljava/util/SortedSet;.c:Ljava/util/Collection;.m:Ljava/util/NavigableMap; 430
+Ljava/io/FileNotFoundException; 431
+Landroid/os/BaseBundle; 432
+Landroid/service/watchdog/ExplicitHealthCheckService$PackageConfig; 433
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.116:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.12:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.90:Ljava/lang/String; 434
+Landroid/icu/text/MessageFormat;.rootLocale:Ljava/util/Locale;.baseLocale:Lsun/util/locale/BaseLocale;.language:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.385:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.107:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.112:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.480:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.550:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.143:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._obsoleteLanguages:[Ljava/lang/String;.1:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.473:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.138:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.204:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.71:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.12:Ljava/lang/String; 434
+Landroid/icu/impl/duration/impl/DataRecord$ETimeLimit;.names:[Ljava/lang/String;.1:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.9:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.99:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages3:[Ljava/lang/String;.152:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.256:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.170:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.220:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.461:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementLanguages:[Ljava/lang/String;.5:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.190:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.157:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._obsoleteCountries:[Ljava/lang/String;.4:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.196:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.117:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.5:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.499:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.199:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.18:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.324:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.101:Ljava/lang/String; 434
+Landroid/icu/impl/locale/UnicodeLocaleExtension;.CA_JAPANESE:Landroid/icu/impl/locale/UnicodeLocaleExtension;._keywords:Ljava/util/SortedMap;.root:Ljava/util/TreeMap$TreeMapEntry;.key:Ljava/lang/Object; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.3:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.140:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.105:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.37:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementCountries:[Ljava/lang/String;.5:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.22:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.103:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.412:Ljava/lang/String; 434
+Landroid/icu/impl/duration/impl/DataRecord$EMilliSupport;.names:[Ljava/lang/String;.1:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.124:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.232:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.219:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.179:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.523:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.75:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.486:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.166:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.112:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.119:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.160:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.298:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.257:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.182:Ljava/lang/String; 434
+Landroid/icu/impl/units/UnitPreferences;.measurementSystem:Ljava/util/Map;.m:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.5:Ljava/util/HashMap$Node;.next:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.47:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.180:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.111:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.358:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.96:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._obsoleteLanguages:[Ljava/lang/String;.0:Ljava/lang/String; 434
+Landroid/icu/text/DateFormat;.HOUR_GENERIC_TZ:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.67:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.254:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.222:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.55:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.349:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.16:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.352:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.443:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.478:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.19:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.401:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.137:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.65:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.474:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.168:Ljava/lang/String; 434
+Landroid/icu/impl/units/UnitPreferences;.measurementSystem:Ljava/util/Map;.m:Ljava/util/Map;.table:[Ljava/util/HashMap$Node;.15:Ljava/util/HashMap$Node;.value:Ljava/lang/Object; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.111:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages3:[Ljava/lang/String;.545:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.30:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.469:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.21:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.69:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.56:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.519:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._replacementLanguages:[Ljava/lang/String;.4:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.107:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.290:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.59:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.220:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.186:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.516:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.181:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.199:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.396:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.117:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.227:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.331:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.447:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.151:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._languages:[Ljava/lang/String;.144:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.132:Ljava/lang/String; 434
+Landroid/icu/impl/LocaleIDs;._countries:[Ljava/lang/String;.230:Ljava/lang/String; 434
+Landroid/icu/text/DateFormat;.MINUTE_SECOND:Ljava/lang/String; 434
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 435
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.head:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 436
+Ljava/lang/Enum;.sharedConstantsCache:Llibcore/util/BasicLruCache;.map:Ljava/util/LinkedHashMap;.tail:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry;.before:Ljava/util/LinkedHashMap$LinkedHashMapEntry; 437
+Landroid/graphics/drawable/ColorStateListDrawable; 438
+Ljava/lang/SecurityException; 439
+Ljava/lang/RuntimeException; 440
+Landroid/media/audiopolicy/AudioProductStrategy; 441
+Landroid/os/PersistableBundle; 442
+Landroid/content/pm/ShortcutInfo; 442
+Landroid/icu/text/TimeZoneFormat;._tzfCache:Landroid/icu/text/TimeZoneFormat$TimeZoneFormatCache;.map:Ljava/util/concurrent/ConcurrentHashMap; 443
+Landroid/graphics/LeakyTypefaceStorage;.sStorage:Ljava/util/ArrayList; 443
+Landroid/graphics/LeakyTypefaceStorage;.sTypefaceMap:Landroid/util/ArrayMap; 443
+Landroid/text/TextWatcher; 444
+Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener; 445
+Ljavax/net/SocketFactory; 446
+Ljava/util/Collections; 447
+Ljava/lang/Exception; 448
+Landroid/os/UserManager; 449
+Landroid/os/RemoteException; 450
+Landroid/content/AttributionSource; 451
+Lcom/android/okhttp/internalandroidapi/HttpURLConnectionFactory$DnsAdapter; 452
+Lcom/android/okhttp/Protocol;.HTTP_2:Lcom/android/okhttp/Protocol; 452
+Ljava/net/Inet4Address; 452
+Lcom/android/okhttp/Protocol;.SPDY_3:Lcom/android/okhttp/Protocol; 452
+Lcom/android/okhttp/OkHttpClient; 452
+Landroid/os/storage/VolumeInfo; 453
+Landroid/os/storage/DiskInfo; 453
+Landroid/view/textclassifier/TextLanguage;.EMPTY:Landroid/view/textclassifier/TextLanguage;.mBundle:Landroid/os/Bundle;.mMap:Landroid/util/ArrayMap; 454
+Ljava/nio/file/StandardOpenOption;.WRITE:Ljava/nio/file/StandardOpenOption; 455
+Ljava/nio/file/StandardOpenOption;.APPEND:Ljava/nio/file/StandardOpenOption; 456
+Ljava/util/logging/FileHandler; 457
+Ljava/nio/file/StandardOpenOption;.CREATE_NEW:Ljava/nio/file/StandardOpenOption; 457
+Ljava/util/logging/FileHandler;.locks:Ljava/util/Set;.map:Ljava/util/HashMap; 457
+Lsun/nio/ch/SharedFileLockTable;.queue:Ljava/lang/ref/ReferenceQueue; 458
+Ljavax/net/ServerSocketFactory; 458
+Landroid/os/AsyncTask; 459
+Landroid/os/strictmode/UnbufferedIoViolation; 460
+Landroid/app/usage/AppStandbyInfo; 461
+Landroid/text/format/DateUtils; 462
+Landroid/security/IKeyChainService; 463
+Landroid/util/Log$TerribleFailure; 464
+Lcom/android/internal/os/RuntimeInit$KillApplicationHandler; 464
+Ljava/util/Timer;.nextSerialNumber:Ljava/util/concurrent/atomic/AtomicInteger; 465
+Landroid/telephony/ims/stub/ImsConfigImplBase$ImsConfigStub; 466
+Landroid/telephony/ims/stub/ImsRegistrationImplBase$1; 466
+Landroid/telephony/ims/ImsUtListener; 466
+Landroid/telephony/ims/feature/MmTelFeature$1; 466
+Lcom/android/ims/ImsManager;.IMS_MANAGER_INSTANCES:Landroid/util/SparseArray;.mValues:[Ljava/lang/Object; 467
+Lcom/android/ims/ImsManager;.IMS_MANAGER_INSTANCES:Landroid/util/SparseArray; 467
+Lcom/android/ims/ImsManager;.IMS_MANAGER_INSTANCES:Landroid/util/SparseArray;.mKeys:[I 467
+Landroid/telephony/ims/aidl/IImsConfig$Stub$Proxy; 468
+Landroid/telephony/ims/aidl/IImsRegistration$Stub$Proxy; 468
+Landroid/telephony/NetworkService; 469
+Landroid/telephony/TelephonyCallback$ServiceStateListener; 470
+Landroid/telephony/TelephonyCallback$PhysicalChannelConfigListener; 471
+Landroid/telephony/TelephonyCallback$RadioPowerStateListener; 471
+Lsun/security/x509/X500Name;.internedOIDs:Ljava/util/Map; 472
+Lsun/security/x509/X500Name;.internedOIDs:Ljava/util/Map;.table:[Ljava/util/HashMap$Node; 472
+Landroid/media/MediaCodec; 473
+Ljava/nio/file/StandardOpenOption;.CREATE:Ljava/nio/file/StandardOpenOption; 474
+Ljava/nio/file/NoSuchFileException; 475
+Ljava/text/DateFormatSymbols;.cachedInstances:Ljava/util/concurrent/ConcurrentMap; 476
+Ljava/util/Currency;.instances:Ljava/util/concurrent/ConcurrentMap; 476
+Ljava/util/Calendar;.cachedLocaleData:Ljava/util/concurrent/ConcurrentMap; 476
+Ljava/text/SimpleDateFormat;.cachedNumberFormatData:Ljava/util/concurrent/ConcurrentMap; 476
+Landroid/app/UriGrantsManager;.IUriGrantsManagerSingleton:Landroid/util/Singleton; 477
+Landroid/content/ContentProviderProxy; 478
+Landroid/os/DeadObjectException; 479
+Landroid/app/slice/SliceSpec; 479
+Landroid/database/sqlite/SQLiteDatabase; 480
+Ljava/util/Locale;.CHINA:Ljava/util/Locale; 481
+Ljava/util/Locale;.TAIWAN:Ljava/util/Locale; 481
+Ljava/util/Locale;.KOREA:Ljava/util/Locale; 481
+Ljava/util/Scanner; 482
+Ljava/math/BigDecimal; 483
+Ljava/security/interfaces/RSAPrivateCrtKey; 483
+Ljava/security/interfaces/RSAPrivateKey; 483
+Lcom/android/server/backup/AccountSyncSettingsBackupHelper;.KEY_ACCOUNT_TYPE:Ljava/lang/String; 483
+Landroid/util/UtilConfig; 484
+Ljava/net/ResponseCache; 485
+Landroid/content/ReceiverCallNotAllowedException; 486
+Landroid/app/ReceiverRestrictedContext; 487
+Landroid/os/strictmode/CredentialProtectedWhileLockedViolation; 488
+Landroid/app/Application; 489
+Ljava/util/NoSuchElementException; 490
+Landroid/os/Messenger; 491
+Landroid/telephony/TelephonyCallback$DataEnabledListener; 491
+Landroid/system/StructLinger; 492
diff --git a/core/api/current.txt b/core/api/current.txt
index d490c3f4d17c..d1d798346c97 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -428,6 +428,7 @@ package android {
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
+ field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final int adServiceTypes;
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -5285,9 +5286,10 @@ package android.app {
field public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START = 21; // 0x15
field public static final int START_TIMESTAMP_RESERVED_RANGE_SYSTEM = 20; // 0x14
field public static final int START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE = 7; // 0x7
- field public static final int START_TYPE_COLD = 0; // 0x0
- field public static final int START_TYPE_HOT = 2; // 0x2
- field public static final int START_TYPE_WARM = 1; // 0x1
+ field public static final int START_TYPE_COLD = 1; // 0x1
+ field public static final int START_TYPE_HOT = 3; // 0x3
+ field public static final int START_TYPE_UNSET = 0; // 0x0
+ field public static final int START_TYPE_WARM = 2; // 0x2
}
public final class AsyncNotedAppOp implements android.os.Parcelable {
@@ -12605,6 +12607,7 @@ package android.content.pm {
method public boolean isStagedSessionApplied();
method public boolean isStagedSessionFailed();
method public boolean isStagedSessionReady();
+ method @FlaggedApi("android.content.pm.archiving") public boolean isUnarchival();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
@@ -13295,6 +13298,7 @@ package android.content.pm {
method @NonNull public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
method @IntRange(from=0xffffffff) public long getLongVersion();
method public String getName();
+ method @FlaggedApi("android.content.pm.sdk_lib_independence") @NonNull public java.util.List<android.content.pm.VersionedPackage> getOptionalDependentPackages();
method public int getType();
method @Deprecated @IntRange(from=0xffffffff) public int getVersion();
method public void writeToParcel(android.os.Parcel, int);
@@ -39071,6 +39075,7 @@ package android.security {
public class NetworkSecurityPolicy {
method public static android.security.NetworkSecurityPolicy getInstance();
+ method @FlaggedApi("android.security.certificate_transparency_configuration") public boolean isCertificateTransparencyVerificationRequired(@NonNull String);
method public boolean isCleartextTrafficPermitted();
method public boolean isCleartextTrafficPermitted(String);
}
@@ -44721,12 +44726,12 @@ package android.telephony {
field public static final int SCAN_TYPE_PERIODIC = 1; // 0x1
}
- public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
- ctor public PhoneNumberFormattingTextWatcher();
- ctor public PhoneNumberFormattingTextWatcher(String);
- method public void afterTextChanged(android.text.Editable);
- method public void beforeTextChanged(CharSequence, int, int, int);
- method public void onTextChanged(CharSequence, int, int, int);
+ @Deprecated public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
+ ctor @Deprecated public PhoneNumberFormattingTextWatcher();
+ ctor @Deprecated @WorkerThread public PhoneNumberFormattingTextWatcher(String);
+ method @Deprecated public void afterTextChanged(android.text.Editable);
+ method @Deprecated public void beforeTextChanged(CharSequence, int, int, int);
+ method @Deprecated public void onTextChanged(CharSequence, int, int, int);
}
public class PhoneNumberUtils {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e7803fbf011d..d395b8cf936e 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -136,6 +136,7 @@ package android.content {
package android.content.pm {
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ method @FlaggedApi("android.content.pm.sdk_lib_independence") @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getOptionalSharedLibraryInfos();
method @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraryInfos();
field public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1; // 0xffffffff
field public static final int HIDDEN_API_ENFORCEMENT_DISABLED = 0; // 0x0
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9a65388c2741..802354e08653 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -656,6 +656,7 @@ package android.app {
field public static final String OPSTR_PLAY_AUDIO = "android:play_audio";
field public static final String OPSTR_POST_NOTIFICATION = "android:post_notification";
field public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
+ field @FlaggedApi("android.view.contentprotection.flags.rapid_clear_notifications_by_listener_app_op_enabled") public static final String OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER = "android:rapid_clear_notifications_by_listener";
field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
field public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
field public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
@@ -4090,7 +4091,7 @@ package android.content.pm {
field @Deprecated public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ANY_USER = 4194304; // 0x400000
- field @Deprecated public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
+ field public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
field @FlaggedApi("android.content.pm.fix_duplicated_flags") public static final long MATCH_CLONE_PROFILE_LONG = 17179869184L; // 0x400000000L
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
@@ -9877,8 +9878,8 @@ package android.nfc.cardemulation {
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getSubsetAids();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getUid();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean hasCategory(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean isCategoryOtherServiceEnabled();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean isOnHost();
- method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean isOtherServiceEnabled();
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadAppLabel(@NonNull android.content.pm.PackageManager);
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.graphics.drawable.Drawable loadBanner(@NonNull android.content.pm.PackageManager);
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
@@ -9887,9 +9888,9 @@ package android.nfc.cardemulation {
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresScreenOn();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setCategoryOtherServiceEnabled(boolean);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
- method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOtherServiceEnabled(boolean);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
}
@@ -12929,6 +12930,7 @@ package android.service.voice {
field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
field public static final int CONFIDENCE_LEVEL_MEDIUM = 2; // 0x2
field public static final int CONFIDENCE_LEVEL_NONE = 0; // 0x0
+ field @FlaggedApi("android.service.voice.flags.allow_hotword_bump_egress") public static final int CONFIDENCE_LEVEL_VERY_HIGH = 4; // 0x4
field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordRejectedResult> CREATOR;
}
@@ -13050,7 +13052,7 @@ package android.service.voice {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.VisualQueryDetector createVisualQueryDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.VisualQueryDetector.Callback);
- method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setIsReceiveSandboxedTrainingDataAllowed(boolean);
+ method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setShouldReceiveSandboxedTrainingData(boolean);
}
}
@@ -13700,6 +13702,7 @@ package android.telephony {
method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
method public int describeContents();
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers();
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_restriction_status") public int getCarrierRestrictionStatus();
method public int getDefaultCarrierRestriction();
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
method public int getMultiSimPolicy();
@@ -14594,6 +14597,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
+ method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCellularIdentifierDisclosureNotificationsEnabled();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
@@ -14641,6 +14645,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
+ method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setEnableCellularIdentifierDisclosureNotifications(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult setIccLockEnabled(boolean, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabled(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
@@ -16984,7 +16989,7 @@ package android.telephony.satellite {
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getSatelliteAttachRestrictionReasonsForCarrier(int);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback) throws android.telephony.satellite.SatelliteManager.SatelliteException;
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateCallback);
@@ -16996,7 +17001,7 @@ package android.telephony.satellite {
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSatelliteSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestNtnSignalStrength(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.NtnSignalStrength,android.telephony.satellite.SatelliteManager.SatelliteException>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestNtnSignalStrength(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.NtnSignalStrength,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index dec1ee52712d..cef11bb42c3f 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1909,6 +1909,8 @@ SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilit
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addAccessibilityStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.view.inputmethod.InputMethodInfo#dump(android.util.Printer, String):
+ SAM-compatible parameters (such as parameter 1, "pw", in android.view.inputmethod.InputMethodInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 39f2737dc880..a3cd3dc87db3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2,6 +2,7 @@
package android {
public static final class Manifest.permission {
+ field @FlaggedApi("com.android.server.accessibility.motion_event_observing") public static final String ACCESSIBILITY_MOTION_EVENT_OBSERVING = "android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING";
field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
@@ -99,6 +100,8 @@ package android.accessibilityservice {
public class AccessibilityServiceInfo implements android.os.Parcelable {
method @NonNull public android.content.ComponentName getComponentName();
+ method @FlaggedApi("android.view.accessibility.motion_event_observing") public int getObservedMotionEventSources();
+ method @FlaggedApi("android.view.accessibility.motion_event_observing") public void setObservedMotionEventSources(int);
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 8ad6ea207665..fc342fa3431a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -20,6 +20,7 @@ import static android.accessibilityservice.util.AccessibilityUtils.getFilteredHt
import static android.accessibilityservice.util.AccessibilityUtils.loadSafeAnimatedImage;
import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -53,6 +54,7 @@ import android.view.InputDevice;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.Flags;
import com.android.internal.R;
import com.android.internal.compat.IPlatformCompat;
@@ -630,7 +632,8 @@ public class AccessibilityServiceInfo implements Parcelable {
InputDevice.SOURCE_TOUCH_NAVIGATION,
InputDevice.SOURCE_ROTARY_ENCODER,
InputDevice.SOURCE_JOYSTICK,
- InputDevice.SOURCE_SENSOR
+ InputDevice.SOURCE_SENSOR,
+ InputDevice.SOURCE_TOUCHSCREEN
})
@Retention(RetentionPolicy.SOURCE)
public @interface MotionEventSources {}
@@ -642,6 +645,8 @@ public class AccessibilityServiceInfo implements Parcelable {
@MotionEventSources
private int mMotionEventSources = 0;
+ private int mObservedMotionEventSources = 0;
+
/**
* Creates a new instance.
*/
@@ -817,6 +822,9 @@ public class AccessibilityServiceInfo implements Parcelable {
mInteractiveUiTimeout = other.mInteractiveUiTimeout;
flags = other.flags;
mMotionEventSources = other.mMotionEventSources;
+ if (Flags.motionEventObserving()) {
+ setObservedMotionEventSources(other.mObservedMotionEventSources);
+ }
// NOTE: Ensure that only properties that are safe to be modified by the service itself
// are included here (regardless of hidden setters, etc.).
}
@@ -1024,16 +1032,75 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public void setMotionEventSources(@MotionEventSources int motionEventSources) {
mMotionEventSources = motionEventSources;
+ mObservedMotionEventSources = 0;
+ }
+
+ /**
+ * Sets the bit mask of {@link android.view.InputDevice} sources that the accessibility service
+ * wants to observe generic {@link android.view.MotionEvent}s from if it has already requested
+ * to listen to them using {@link #setMotionEventSources(int)}. Events from these sources will
+ * be sent to the rest of the input pipeline without being consumed by accessibility services.
+ * This service will still be able to see them.
+ *
+ * <p><strong>Note:</strong> you will need to call this function every time you call {@link
+ * #setMotionEventSources(int)}. Calling {@link #setMotionEventSources(int)} clears the list of
+ * observed motion event sources for this service.
+ *
+ * <p><strong>Note:</strong> {@link android.view.InputDevice} sources contain source class bits
+ * that complicate bitwise flag removal operations. To remove a specific source you should
+ * rebuild the entire value using bitwise OR operations on the individual source constants.
+ *
+ * <p>Including an {@link android.view.InputDevice} source that does not send {@link
+ * android.view.MotionEvent}s is effectively a no-op for that source, since you will not receive
+ * any events from that source.
+ *
+ * <p><strong>Note:</strong> Calling this function with a source that has not been listened to
+ * using {@link #setMotionEventSources(int)} will throw an exception.
+ *
+ * @see AccessibilityService#onMotionEvent
+ * @see #MotionEventSources
+ * @see #setMotionEventSources(int)
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MOTION_EVENT_OBSERVING)
+ @TestApi
+ public void setObservedMotionEventSources(int observedMotionEventSources) {
+ // Confirm that any sources requested here have already been requested for listening.
+ if ((observedMotionEventSources & ~mMotionEventSources) != 0) {
+ String message =
+ String.format(
+ "Requested motion event sources for listening = 0x%x but requested"
+ + " motion event sources for observing = 0x%x.",
+ mMotionEventSources, observedMotionEventSources);
+ throw new IllegalArgumentException(message);
+ }
+ mObservedMotionEventSources = observedMotionEventSources;
+ }
+
+ /**
+ * Returns the bit mask of {@link android.view.InputDevice} sources that the accessibility
+ * service wants to observe generic {@link android.view.MotionEvent}s from if it has already
+ * requested to listen to them using {@link #setMotionEventSources(int)}. Events from these
+ * sources will be sent to the rest of the input pipeline without being consumed by
+ * accessibility services. This service will still be able to see them.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MOTION_EVENT_OBSERVING)
+ @MotionEventSources
+ @TestApi
+ public int getObservedMotionEventSources() {
+ return mObservedMotionEventSources;
}
/**
* The localized summary of the accessibility service.
- * <p>
- * <strong>Statically set from
- * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
- * </p>
- * @return The localized summary if available, and {@code null} if a summary
- * has not been provided.
+ *
+ * <p><strong>Statically set from {@link AccessibilityService#SERVICE_META_DATA
+ * meta-data}.</strong>
+ *
+ * @return The localized summary if available, and {@code null} if a summary has not been
+ * provided.
*/
public CharSequence loadSummary(PackageManager packageManager) {
if (mSummaryResId == 0) {
@@ -1260,6 +1327,7 @@ public class AccessibilityServiceInfo implements Parcelable {
parcel.writeString(mTileServiceName);
parcel.writeInt(mIntroResId);
parcel.writeInt(mMotionEventSources);
+ parcel.writeInt(mObservedMotionEventSources);
}
private void initFromParcel(Parcel parcel) {
@@ -1285,6 +1353,8 @@ public class AccessibilityServiceInfo implements Parcelable {
mTileServiceName = parcel.readString();
mIntroResId = parcel.readInt();
mMotionEventSources = parcel.readInt();
+ // use the setter here because it throws an exception for invalid values.
+ setObservedMotionEventSources(parcel.readInt());
}
@Override
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ffed40538702..5674a108baaa 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3061,10 +3061,10 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Request to put the a freeform activity into fullscreen. This will only be allowed if the
- * activity is on a freeform display, such as a desktop device. The requester has to be the
- * top-most activity of the focused display, and the request should be a response to a user
- * input. When getting fullscreen and receiving corresponding
+ * Request to put the freeform activity into fullscreen. The requester has to be the top-most
+ * activity of the focused display which can be verified using
+ * {@link #onTopResumedActivityChanged(boolean)}. The request should also be a response to a
+ * user input. When getting fullscreen and receiving corresponding
* {@link #onConfigurationChanged(Configuration)} and
* {@link #onMultiWindowModeChanged(boolean, Configuration)}, the activity should relayout
* itself and the system bars' visibilities can be controlled as usual fullscreen apps.
@@ -3072,11 +3072,6 @@ public class Activity extends ContextThemeWrapper
* Calling it again with the exit request can restore the activity to the previous status.
* This will only happen when it got into fullscreen through this API.
*
- * If an app wants to be in fullscreen always, it should claim as not being resizable
- * by setting
- * <a href="https://developer.android.com/guide/topics/large-screens/multi-window-support#resizeableActivity">
- * {@code android:resizableActivity="false"}</a> instead of calling this API.
- *
* @param request Can be {@link #FULLSCREEN_MODE_REQUEST_ENTER} or
* {@link #FULLSCREEN_MODE_REQUEST_EXIT} to indicate this request is to get
* fullscreen or get restored.
@@ -6884,8 +6879,8 @@ public class Activity extends ContextThemeWrapper
* application package was involved.
*
* <p>If called while inside the handling of {@link #onNewIntent}, this function will
- * return the referrer that submitted that new intent to the activity. Otherwise, it
- * always returns the referrer of the original Intent.</p>
+ * return the referrer that submitted that new intent to the activity only after
+ * {@link #setIntent(Intent)} is called with the provided intent.</p>
*
* <p>Note that this is <em>not</em> a security feature -- you can not trust the
* referrer information, applications can spoof it.</p>
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8b39ed6fb411..6ddb36a72aa9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4077,7 +4077,7 @@ public final class ActivityThread extends ClientTransactionHandler
final LoadedApk sdkApk = getPackageInfo(
contextInfo.getSdkApplicationInfo(),
r.packageInfo.getCompatibilityInfo(),
- ActivityContextInfo.CONTEXT_FLAGS);
+ contextInfo.getContextFlags());
final ContextImpl activityContext = ContextImpl.createActivityContext(
this, sdkApk, r.activityInfo, r.token, displayId, r.overrideConfig);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ec43184bd42c..4b24b1f2b2a1 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -18,6 +18,7 @@ package android.app;
import static android.permission.flags.Flags.FLAG_OP_ENABLE_MOBILE_DATA_BY_USER;
import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED;
+import static android.view.contentprotection.flags.Flags.FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED;
import static java.lang.Long.max;
@@ -1508,6 +1509,7 @@ public class AppOpsManager {
*/
public static final int OP_CREATE_ACCESSIBILITY_OVERLAY =
AppProtoEnums.APP_OP_CREATE_ACCESSIBILITY_OVERLAY;
+
/**
* Indicate that the user has enabled or disabled mobile data
* @hide
@@ -1529,9 +1531,17 @@ public class AppOpsManager {
*/
public static final int OP_RESERVED_FOR_TESTING = AppProtoEnums.APP_OP_RESERVED_FOR_TESTING;
+ /**
+ * Rapid clearing of notifications by a notification listener, see b/289080543 for details
+ *
+ * @hide
+ */
+ public static final int OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER =
+ AppProtoEnums.APP_OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 142;
+ public static final int _NUM_OP = 143;
/**
* All app ops represented as strings.
@@ -1680,6 +1690,7 @@ public class AppOpsManager {
OPSTR_MEDIA_ROUTING_CONTROL,
OPSTR_ENABLE_MOBILE_DATA_BY_USER,
OPSTR_RESERVED_FOR_TESTING,
+ OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
})
public @interface AppOpString {}
@@ -2330,6 +2341,7 @@ public class AppOpsManager {
@FlaggedApi(FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED)
public static final String OPSTR_CREATE_ACCESSIBILITY_OVERLAY =
"android:create_accessibility_overlay";
+
/**
* Indicate that the user has enabled or disabled mobile data
* @hide
@@ -2350,6 +2362,16 @@ public class AppOpsManager {
public static final String OPSTR_RESERVED_FOR_TESTING =
"android:reserved_for_testing";
+ /**
+ * Rapid clearing of notifications by a notification listener, see b/289080543 for details
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED)
+ public static final String OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER =
+ "android:rapid_clear_notifications_by_listener";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2909,6 +2931,10 @@ public class AppOpsManager {
"ENABLE_MOBILE_DATA_BY_USER").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_RESERVED_FOR_TESTING, OPSTR_RESERVED_FOR_TESTING,
"OP_RESERVED_FOR_TESTING").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
+ OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
+ "RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
};
// The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 87c86df6140d..287d2bd9e6a7 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2909,7 +2909,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
launcherExtras, dialogInfo, flags, mContext.getOpPackageName(),
- getUserId());
+ UserHandle.myUserId() /* suspendingUserId */, getUserId() /* targetUserId */);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
index c8317c8faad5..656feb0401d6 100644
--- a/core/java/android/app/ApplicationStartInfo.java
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -104,14 +104,17 @@ public final class ApplicationStartInfo implements Parcelable {
/** Process started due to Activity started for any reason not explicitly listed. */
public static final int START_REASON_START_ACTIVITY = 11;
+ /** Start type not yet set. */
+ public static final int START_TYPE_UNSET = 0;
+
/** Process started from scratch. */
- public static final int START_TYPE_COLD = 0;
+ public static final int START_TYPE_COLD = 1;
/** Process retained minimally SavedInstanceState. */
- public static final int START_TYPE_WARM = 1;
+ public static final int START_TYPE_WARM = 2;
/** Process brought back to foreground. */
- public static final int START_TYPE_HOT = 2;
+ public static final int START_TYPE_HOT = 3;
/**
* Default. The system always creates a new instance of the activity in the target task and
@@ -277,6 +280,7 @@ public final class ApplicationStartInfo implements Parcelable {
@IntDef(
prefix = {"START_TYPE_"},
value = {
+ START_TYPE_UNSET,
START_TYPE_COLD,
START_TYPE_WARM,
START_TYPE_HOT,
@@ -769,6 +773,7 @@ public final class ApplicationStartInfo implements Parcelable {
private static String startTypeToString(@StartType int startType) {
return switch (startType) {
+ case START_TYPE_UNSET -> "UNSET";
case START_TYPE_COLD -> "COLD";
case START_TYPE_WARM -> "WARM";
case START_TYPE_HOT -> "HOT";
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index d93544972e7a..343348b89625 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,6 +16,8 @@
package android.app;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.annotation.DrawableRes;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -390,7 +392,7 @@ public final class AutomaticZenRule implements Parcelable {
*/
@FlaggedApi(Flags.FLAG_MODES_API)
public void setType(@Type int type) {
- mType = type;
+ mType = checkValidType(type);
}
/**
@@ -451,6 +453,24 @@ public final class AutomaticZenRule implements Parcelable {
mAllowManualInvocation = allowManualInvocation;
}
+ /** @hide */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public void validate() {
+ if (Flags.modesApi()) {
+ checkValidType(mType);
+ }
+ }
+
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ @Type
+ private static int checkValidType(@Type int type) {
+ checkArgument(type >= TYPE_UNKNOWN && type <= TYPE_MANAGED,
+ "Rule type must be one of TYPE_UNKNOWN, TYPE_OTHER, TYPE_SCHEDULE_TIME, "
+ + "TYPE_SCHEDULE_CALENDAR, TYPE_BEDTIME, TYPE_DRIVING, TYPE_IMMERSIVE, "
+ + "TYPE_THEATER, or TYPE_MANAGED");
+ return type;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -625,8 +645,8 @@ public final class AutomaticZenRule implements Parcelable {
}
public Builder(@NonNull String name, @NonNull Uri conditionId) {
- mName = name;
- mConditionId = conditionId;
+ mName = Objects.requireNonNull(name);
+ mConditionId = Objects.requireNonNull(conditionId);
}
/**
@@ -703,10 +723,10 @@ public final class AutomaticZenRule implements Parcelable {
}
/**
- * Sets the type of the rule
+ * Sets the type of the rule.
*/
public @NonNull Builder setType(@Type int type) {
- mType = type;
+ mType = checkValidType(type);
return this;
}
@@ -714,7 +734,7 @@ public final class AutomaticZenRule implements Parcelable {
* Sets a user visible description of when this rule will be active
* (see {@link Condition#STATE_TRUE}).
*
- * A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
+ * <p>A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
* "When connected to [Car Name]".
*/
public @NonNull Builder setTriggerDescription(@Nullable String description) {
diff --git a/core/java/android/app/FullscreenRequestHandler.java b/core/java/android/app/FullscreenRequestHandler.java
index 52f461daf233..c78c66aa62c0 100644
--- a/core/java/android/app/FullscreenRequestHandler.java
+++ b/core/java/android/app/FullscreenRequestHandler.java
@@ -16,8 +16,7 @@
package android.app;
-import static android.app.Activity.FULLSCREEN_MODE_REQUEST_ENTER;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.Activity.FULLSCREEN_MODE_REQUEST_EXIT;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.annotation.IntDef;
@@ -35,18 +34,14 @@ import android.os.OutcomeReceiver;
public class FullscreenRequestHandler {
@IntDef(prefix = { "RESULT_" }, value = {
RESULT_APPROVED,
- RESULT_FAILED_NOT_IN_FREEFORM,
RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY,
- RESULT_FAILED_NOT_DEFAULT_FREEFORM,
RESULT_FAILED_NOT_TOP_FOCUSED
})
public @interface RequestResult {}
public static final int RESULT_APPROVED = 0;
- public static final int RESULT_FAILED_NOT_IN_FREEFORM = 1;
- public static final int RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY = 2;
- public static final int RESULT_FAILED_NOT_DEFAULT_FREEFORM = 3;
- public static final int RESULT_FAILED_NOT_TOP_FOCUSED = 4;
+ public static final int RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY = 1;
+ public static final int RESULT_FAILED_NOT_TOP_FOCUSED = 2;
public static final String REMOTE_CALLBACK_RESULT_KEY = "result";
@@ -85,17 +80,10 @@ public class FullscreenRequestHandler {
OutcomeReceiver<Void, Throwable> callback, int result) {
Throwable e = null;
switch (result) {
- case RESULT_FAILED_NOT_IN_FREEFORM:
- e = new IllegalStateException("The window is not a freeform window, the request "
- + "to get into fullscreen cannot be approved.");
- break;
case RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY:
e = new IllegalStateException("The window is not in fullscreen by calling the "
+ "requestFullscreenMode API before, such that cannot be restored.");
break;
- case RESULT_FAILED_NOT_DEFAULT_FREEFORM:
- e = new IllegalStateException("The window is not launched in freeform by default.");
- break;
case RESULT_FAILED_NOT_TOP_FOCUSED:
e = new IllegalStateException("The window is not the top focused window.");
break;
@@ -109,11 +97,7 @@ public class FullscreenRequestHandler {
}
private static int earlyCheckRequestMatchesWindowingMode(int request, int windowingMode) {
- if (request == FULLSCREEN_MODE_REQUEST_ENTER) {
- if (windowingMode != WINDOWING_MODE_FREEFORM) {
- return RESULT_FAILED_NOT_IN_FREEFORM;
- }
- } else {
+ if (request == FULLSCREEN_MODE_REQUEST_EXIT) {
if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
return RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY;
}
diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index 9a818e49ae4a..bfec9430fd58 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -52,4 +52,6 @@ interface IGameManagerService {
void removeGameModeListener(IGameModeListener gameModeListener);
void addGameStateListener(IGameStateListener gameStateListener);
void removeGameStateListener(IGameStateListener gameStateListener);
+ @EnforcePermission("MANAGE_GAME_MODE")
+ void toggleGameDefaultFrameRate(boolean isEnabled);
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 90a265937082..4a6349b1b02f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9381,7 +9381,7 @@ public class DevicePolicyManager {
@Deprecated
@SystemApi
@RequiresPermission(MANAGE_DEVICE_ADMINS)
- public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName)
+ public boolean setActiveProfileOwner(@NonNull ComponentName admin, String ownerName)
throws IllegalArgumentException {
throwIfParentInstance("setActiveProfileOwner");
if (mService != null) {
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6e451479c5a4..4cf9fcab9092 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -16,6 +16,8 @@
package android.appwidget;
+import static android.appwidget.flags.Flags.remoteAdapterConversion;
+
import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -566,11 +568,9 @@ public class AppWidgetManager {
private void tryAdapterConversion(
FunctionalUtils.RemoteExceptionIgnoringConsumer<RemoteViews> action,
RemoteViews original, String failureMsg) {
- final boolean isConvertingAdapter = RemoteViews.isAdapterConversionEnabled()
+ if (remoteAdapterConversion()
&& (mHasPostedLegacyLists = mHasPostedLegacyLists
- || (original != null && original.hasLegacyLists()));
-
- if (isConvertingAdapter) {
+ || (original != null && original.hasLegacyLists()))) {
final RemoteViews viewsCopy = new RemoteViews(original);
Runnable updateWidgetWithTask = () -> {
try {
@@ -587,13 +587,12 @@ public class AppWidgetManager {
}
updateWidgetWithTask.run();
- return;
- }
-
- try {
- action.acceptOrThrow(original);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
+ } else {
+ try {
+ action.acceptOrThrow(original);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
}
@@ -838,22 +837,20 @@ public class AppWidgetManager {
return;
}
- if (!RemoteViews.isAdapterConversionEnabled()) {
+ if (remoteAdapterConversion()) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ mHasPostedLegacyLists = true;
+ createUpdateExecutorIfNull().execute(() -> notifyCollectionWidgetChange(
+ appWidgetIds, viewId));
+ } else {
+ notifyCollectionWidgetChange(appWidgetIds, viewId);
+ }
+ } else {
try {
mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
-
- return;
- }
-
- if (Looper.myLooper() == Looper.getMainLooper()) {
- mHasPostedLegacyLists = true;
- createUpdateExecutorIfNull().execute(() -> notifyCollectionWidgetChange(appWidgetIds,
- viewId));
- } else {
- notifyCollectionWidgetChange(appWidgetIds, viewId);
}
}
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 6a735a418b58..c95b864c08bb 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -6,3 +6,10 @@ flag {
description: "Enable support for generated previews in AppWidgetManager"
bug: "306546610"
}
+
+flag {
+ name: "remote_adapter_conversion"
+ namespace: "app_widgets"
+ description: "Enable adapter conversion to RemoteCollectionItemsAdapter"
+ bug: "245950570"
+} \ No newline at end of file
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index e4a03c596254..d5b5f40a6980 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -37,6 +37,7 @@ import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
@@ -709,7 +710,9 @@ public final class CompanionDeviceManager {
IntentSender intentSender = mService
.requestNotificationAccess(component, mContext.getUserId())
.getIntentSender();
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ mContext.startIntentSender(intentSender, null, 0, 0, 0,
+ ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (IntentSender.SendIntentException e) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 16a80e93326a..3713380485ea 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -19,6 +19,7 @@ package android.content.pm;
import static android.os.Build.VERSION_CODES.DONUT;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1065,11 +1066,25 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
* the structure.
*
+ * NOTE: the list also contains the result of {@link #getOptionalSharedLibraryInfos}.
+ *
* {@hide}
*/
+ @Nullable
public List<SharedLibraryInfo> sharedLibraryInfos;
/**
+ * List of all shared libraries this application is optionally linked against.
+ * This field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
+ * the structure.
+ *
+ * @hide
+ */
+ @Nullable
+ public List<SharedLibraryInfo> optionalSharedLibraryInfos;
+
+ /**
* Full path to the default directory assigned to the package for its
* persistent data.
*/
@@ -1937,6 +1952,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
seInfoUser = orig.seInfoUser;
sharedLibraryFiles = orig.sharedLibraryFiles;
sharedLibraryInfos = orig.sharedLibraryInfos;
+ optionalSharedLibraryInfos = orig.optionalSharedLibraryInfos;
dataDir = orig.dataDir;
deviceProtectedDataDir = orig.deviceProtectedDataDir;
credentialProtectedDataDir = orig.credentialProtectedDataDir;
@@ -2029,6 +2045,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString8(seInfoUser);
dest.writeString8Array(sharedLibraryFiles);
dest.writeTypedList(sharedLibraryInfos);
+ dest.writeTypedList(optionalSharedLibraryInfos);
dest.writeString8(dataDir);
dest.writeString8(deviceProtectedDataDir);
dest.writeString8(credentialProtectedDataDir);
@@ -2129,6 +2146,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
seInfoUser = source.readString8();
sharedLibraryFiles = source.createString8Array();
sharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
+ optionalSharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
dataDir = source.readString8();
deviceProtectedDataDir = source.readString8();
credentialProtectedDataDir = source.readString8();
@@ -2760,6 +2778,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
* PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
*
+ * NOTE: the list also contains the result of {@link #getOptionalSharedLibraryInfos}.
+ *
* @hide
*/
@NonNull
@@ -2772,6 +2792,23 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/**
+ * List of all shared libraries this application is optionally linked against. This
+ * list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @FlaggedApi(Flags.FLAG_SDK_LIB_INDEPENDENCE)
+ public List<SharedLibraryInfo> getOptionalSharedLibraryInfos() {
+ if (optionalSharedLibraryInfos == null) {
+ return Collections.EMPTY_LIST;
+ }
+ return optionalSharedLibraryInfos;
+ }
+
+ /**
* Gets the trusted host certificate digests of apps that are allowed to embed activities of
* this application. The digests are computed using the SHA-256 digest algorithm.
* @see android.R.attr#knownActivityEmbeddingCerts
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index e9f419e9a8ce..a97de6368b8c 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -64,6 +64,9 @@ interface ILauncherApps {
PendingIntent getActivityLaunchIntent(String callingPackage, in ComponentName component,
in UserHandle user);
LauncherUserInfo getLauncherUserInfo(in UserHandle user);
+ List<String> getPreInstalledSystemPackages(in UserHandle user);
+ IntentSender getAppMarketActivityIntent(String callingPackage, String packageName,
+ in UserHandle user);
void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 98623de810c4..6dc8d4738c87 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -300,7 +300,8 @@ interface IPackageManager {
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
- in SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId);
+ in SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
+ int suspendingUserId, int targetUserId);
String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 0cd4358b2c91..1d2b1aff46bc 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -799,6 +799,78 @@ public class LauncherApps {
}
}
+
+ /**
+ * Returns an intent sender which can be used to start the App Market activity (Installer
+ * Activity).
+ * This method is primarily used to get an intent sender which starts App Market activity for
+ * another profile, if the caller is not otherwise allowed to start activity in that profile.
+ *
+ * <p>When packageName is set, intent sender to start the App Market Activity which installed
+ * the package in calling user will be returned, but for the profile passed.
+ *
+ * <p>When packageName is not set, intent sender to launch the default App Market Activity for
+ * the profile will be returned. In case there are multiple App Market Activities available for
+ * the profile, IntentPicker will be started, allowing user to choose the preferred activity.
+ *
+ * <p>The method will fall back to the behaviour of not having the packageName set, in case:
+ * <ul>
+ * <li>No activity for the packageName is found in calling user-space.</li>
+ * <li>The App Market Activity which installed the package in calling user-space is not
+ * present.</li>
+ * <li>The App Market Activity which installed the package in calling user-space is not
+ * present in the profile passed.</li>
+ * </ul>
+ * </p>
+ *
+ *
+ *
+ * @param packageName the package for which intent sender to launch App Market Activity is
+ * required.
+ * @param user the profile for which intent sender to launch App Market Activity is required.
+ * @return {@link IntentSender} object which launches the App Market Activity, null in case
+ * there is no such activity.
+ * @hide
+ */
+ @Nullable
+ @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+ public IntentSender getAppMarketActivityIntent(@Nullable String packageName,
+ @NonNull UserHandle user) {
+ if (DEBUG) {
+ Log.i(TAG, "getAppMarketActivityIntent for package: " + packageName
+ + " user: " + user);
+ }
+ try {
+ return mService.getAppMarketActivityIntent(mContext.getPackageName(),
+ packageName, user);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the list of the system packages that are installed at user creation.
+ *
+ * <p>An empty list denotes that all system packages are installed for that user at creation.
+ * This behaviour is inherited from the underlining UserManager API.
+ *
+ * @param userHandle the user for which installed system packages are required.
+ * @return {@link List} of {@link String}, representing the package name of the installed
+ * package. Can be empty but not null.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+ public List<String> getPreInstalledSystemPackages(@NonNull UserHandle userHandle) {
+ if (DEBUG) {
+ Log.i(TAG, "getPreInstalledSystemPackages for user: " + userHandle);
+ }
+ try {
+ return mService.getPreInstalledSystemPackages(userHandle);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
/**
* Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
* returns null.
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 5dee65b62201..4f61613b9c6e 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -231,7 +231,7 @@ public class PackageInfo implements Parcelable {
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
* the corresponding entry in {@link #requestedPermissions}, and will have
- * the flags {@link #REQUESTED_PERMISSION_GRANTED} and
+ * the flags {@link #REQUESTED_PERMISSION_GRANTED}, {@link #REQUESTED_PERMISSION_IMPLICIT}, and
* {@link #REQUESTED_PERMISSION_NEVER_FOR_LOCATION} set as appropriate.
*/
@Nullable
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e395127dfaf3..0e131b413d0c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -4381,6 +4381,17 @@ public class PackageInstaller {
return pendingUserActionReason;
}
+ /**
+ * Returns true if the session is an unarchival.
+ *
+ * @see PackageInstaller#requestUnarchive
+ */
+ @FlaggedApi(Flags.FLAG_ARCHIVING)
+ public boolean isUnarchival() {
+ return (installFlags & PackageManager.INSTALL_UNARCHIVE) != 0;
+ }
+
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e2243292ab8d..a8638708824b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1225,12 +1225,10 @@ public abstract class PackageManager {
public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
/**
- * @deprecated Use {@link #MATCH_CLONE_PROFILE_LONG} instead.
+ * Use {@link #MATCH_CLONE_PROFILE_LONG} instead.
*
* @hide
*/
- @SuppressLint("UnflaggedApi") // Just adding the @Deprecated annotation
- @Deprecated
@SystemApi
public static final int MATCH_CLONE_PROFILE = 0x20000000;
@@ -1519,6 +1517,7 @@ public abstract class PackageManager {
INSTALL_REQUEST_UPDATE_OWNERSHIP,
INSTALL_IGNORE_DEXOPT_PROFILE,
INSTALL_UNARCHIVE_DRAFT,
+ INSTALL_UNARCHIVE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -1766,13 +1765,22 @@ public abstract class PackageManager {
* If set, then the session is a draft session created for an upcoming unarchival by its
* installer.
*
- * @see PackageInstaller#requestUnarchive(String)
+ * @see PackageInstaller#requestUnarchive
*
* @hide
*/
public static final int INSTALL_UNARCHIVE_DRAFT = 1 << 29;
/**
+ * If set, then the {@link PackageInstaller.Session} is an unarchival.
+ *
+ * @see PackageInstaller#requestUnarchive
+ *
+ * @hide
+ */
+ public static final int INSTALL_UNARCHIVE = 1 << 30;
+
+ /**
* Flag parameter for {@link #installPackage} to force a non-staged update of an APEX. This is
* a development-only feature and should not be used on end user devices.
*
@@ -6302,6 +6310,11 @@ public abstract class PackageManager {
/**
* Check whether a particular package has been granted a particular
* permission.
+ * <p>
+ * <strong>Note: </strong>This API returns the underlying permission state
+ * as-is and is mostly intended for permission managing system apps. To
+ * perform an access check for a certain app, please use the
+ * {@link Context#checkPermission} APIs instead.
*
* @param permName The name of the permission you are checking for.
* @param packageName The name of the package you are checking against.
@@ -9987,6 +10000,9 @@ public abstract class PackageManager {
* device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
* {@link android.Manifest.permission#SUSPEND_APPS}.
*
+ * <p>
+ * <strong>Note:</strong>This API doesn't support cross user suspension and should only be used
+ * for testing.
* @param suspendedPackage The package that has been suspended.
* @return Name of the package that suspended the given package. Returns {@code null} if the
* given package is not currently suspended and the platform package name - i.e.
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 25ba72551b04..5acebf54a159 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -23,6 +24,7 @@ import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Pair;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -99,26 +101,61 @@ public final class SharedLibraryInfo implements Parcelable {
private final boolean mIsNative;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
+
+ private final List<VersionedPackage> mOptionalDependentPackages;
private List<SharedLibraryInfo> mDependencies;
/**
* Creates a new instance.
*
+ * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of
+ * jars of
+ * this shared library. Null for builtin library.
+ * @param name The lib name.
+ * @param version The lib version if not builtin.
+ * @param type The lib type.
+ * @param declaringPackage The package that declares the library.
+ * @param dependentPackages The packages that depend on the library.
+ * @param isNative indicate if this shared lib is a native lib or not (i.e. java)
+ * @hide
+ */
+ public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
+ String name, long version, int type,
+ VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
+ List<SharedLibraryInfo> dependencies, boolean isNative) {
+ mPath = path;
+ mPackageName = packageName;
+ mCodePaths = codePaths;
+ mName = name;
+ mVersion = version;
+ mType = type;
+ mDeclaringPackage = declaringPackage;
+ mDependentPackages = dependentPackages;
+ mDependencies = dependencies;
+ mIsNative = isNative;
+ mOptionalDependentPackages = null;
+ }
+
+ /**
+ * Creates a new instance.
+ *
* @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
* this shared library. Null for builtin library.
* @param name The lib name.
* @param version The lib version if not builtin.
* @param type The lib type.
* @param declaringPackage The package that declares the library.
- * @param dependentPackages The packages that depend on the library.
* @param isNative indicate if this shared lib is a native lib or not (i.e. java)
+ * @param allDependentPackages All packages that depend on the library (including the optional
+ * sdk libraries).
*
* @hide
*/
public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
String name, long version, int type,
- VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
- List<SharedLibraryInfo> dependencies, boolean isNative) {
+ VersionedPackage declaringPackage,
+ List<SharedLibraryInfo> dependencies, boolean isNative,
+ Pair<List<VersionedPackage>, List<Boolean>> allDependentPackages) {
mPath = path;
mPackageName = packageName;
mCodePaths = codePaths;
@@ -126,9 +163,28 @@ public final class SharedLibraryInfo implements Parcelable {
mVersion = version;
mType = type;
mDeclaringPackage = declaringPackage;
- mDependentPackages = dependentPackages;
mDependencies = dependencies;
mIsNative = isNative;
+
+ var allDependents = allDependentPackages.first;
+ var usesLibOptional = allDependentPackages.second;
+ mDependentPackages = allDependents;
+ List<VersionedPackage> optionalDependents = null;
+ if (mType == SharedLibraryInfo.TYPE_SDK_PACKAGE
+ && Flags.sdkLibIndependence() && allDependents != null
+ && usesLibOptional != null
+ && allDependents.size() == usesLibOptional.size()) {
+ for (int k = 0; k < allDependents.size(); k++) {
+ VersionedPackage versionedPackage = allDependents.get(k);
+ if (usesLibOptional.get(k)) {
+ if (optionalDependents == null) {
+ optionalDependents = new ArrayList<>();
+ }
+ optionalDependents.add(versionedPackage);
+ }
+ }
+ }
+ mOptionalDependentPackages = optionalDependents;
}
private SharedLibraryInfo(Parcel parcel) {
@@ -148,6 +204,8 @@ public final class SharedLibraryInfo implements Parcelable {
parcel.readArrayList(null, android.content.pm.VersionedPackage.class);
mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR);
mIsNative = parcel.readBoolean();
+ mOptionalDependentPackages = parcel.readParcelableList(new ArrayList<>(),
+ VersionedPackage.class.getClassLoader(), VersionedPackage.class);
}
/**
@@ -324,6 +382,8 @@ public final class SharedLibraryInfo implements Parcelable {
/**
* Gets the packages that depend on the library.
*
+ * NOTE: the list also contains the result of {@link #getOptionalDependentPackages}.
+ *
* @return The dependent packages.
*/
public @NonNull List<VersionedPackage> getDependentPackages() {
@@ -333,6 +393,19 @@ public final class SharedLibraryInfo implements Parcelable {
return mDependentPackages;
}
+ /**
+ * Gets the packages that optionally depend on the library.
+ *
+ * @return The dependent packages.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_LIB_INDEPENDENCE)
+ public @NonNull List<VersionedPackage> getOptionalDependentPackages() {
+ if (mOptionalDependentPackages == null) {
+ return Collections.emptyList();
+ }
+ return mOptionalDependentPackages;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -362,6 +435,7 @@ public final class SharedLibraryInfo implements Parcelable {
parcel.writeList(mDependentPackages);
parcel.writeTypedList(mDependencies);
parcel.writeBoolean(mIsNative);
+ parcel.writeParcelableList(mOptionalDependentPackages, flags);
}
private static String typeToString(int type) {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 6c6b33b8d716..57025c25f97b 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -49,3 +49,10 @@ flag {
description: "Add support to unlock the private space using biometrics"
bug: "312184187"
}
+
+flag {
+ name: "support_autolock_for_private_space"
+ namespace: "profile_experiences"
+ description: "Add support to lock private space automatically after a time period"
+ bug: "303201022"
+}
diff --git a/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl b/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl
new file mode 100644
index 000000000000..73ac333cfd89
--- /dev/null
+++ b/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.hardware.biometrics;
+
+/**
+ * Low-level callback interface between <Biometric>Manager and <Auth>Service. Allows core system
+ * services (e.g. SystemUI) to register a listener for updates about the current state of biometric
+ * authentication.
+ * @hide
+ */
+oneway interface AuthenticationStateListener {
+ /**
+ * Defines behavior in response to authentication starting
+ * @param requestReason reason from [BiometricRequestConstants.RequestReason] for requesting
+ * authentication starting
+ */
+ void onAuthenticationStarted(int requestReason);
+
+ /**
+ * Defines behavior in response to authentication stopping
+ */
+ void onAuthenticationStopped();
+}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index f82f79eba8c9..d7d1d1a7c677 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -552,6 +552,44 @@ public class BiometricManager {
}
/**
+ * Registers listener for changes to biometric authentication state.
+ * Only sends callbacks for events that occur after the callback has been registered.
+ * @param listener Listener for changes to biometric authentication state
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void registerAuthenticationStateListener(AuthenticationStateListener listener) {
+ if (mService != null) {
+ try {
+ mService.registerAuthenticationStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "registerAuthenticationStateListener(): Service not connected");
+ }
+ }
+
+ /**
+ * Unregisters listener for changes to biometric authentication state.
+ * @param listener Listener for changes to biometric authentication state
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void unregisterAuthenticationStateListener(AuthenticationStateListener listener) {
+ if (mService != null) {
+ try {
+ mService.unregisterAuthenticationStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "unregisterAuthenticationStateListener(): Service not connected");
+ }
+ }
+
+
+ /**
* Requests all {@link Authenticators.Types#BIOMETRIC_STRONG} sensors to have their
* authenticatorId invalidated for the specified user. This happens when enrollments have been
* added on devices with multiple biometric sensors.
diff --git a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java b/core/java/android/hardware/biometrics/BiometricRequestConstants.java
index 065ae64a92ad..b036f309f7df 100644
--- a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricRequestConstants.java
@@ -22,24 +22,27 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Common constants for biometric overlays.
+ * Common constants for biometric requests.
* @hide
*/
-public interface BiometricOverlayConstants {
+public class BiometricRequestConstants {
+
+ private BiometricRequestConstants() {}
+
/** Unknown usage. */
- int REASON_UNKNOWN = 0;
+ public static final int REASON_UNKNOWN = 0;
/** User is about to enroll. */
- int REASON_ENROLL_FIND_SENSOR = 1;
+ public static final int REASON_ENROLL_FIND_SENSOR = 1;
/** User is enrolling. */
- int REASON_ENROLL_ENROLLING = 2;
+ public static final int REASON_ENROLL_ENROLLING = 2;
/** Usage from BiometricPrompt. */
- int REASON_AUTH_BP = 3;
- /** Usage from Keyguard. */
- int REASON_AUTH_KEYGUARD = 4;
+ public static final int REASON_AUTH_BP = 3;
+ /** Usage from Device Entry. */
+ public static final int REASON_AUTH_KEYGUARD = 4;
/** Non-specific usage (from FingerprintManager). */
- int REASON_AUTH_OTHER = 5;
+ public static final int REASON_AUTH_OTHER = 5;
/** Usage from Settings. */
- int REASON_AUTH_SETTINGS = 6;
+ public static final int REASON_AUTH_SETTINGS = 6;
@IntDef({REASON_UNKNOWN,
REASON_ENROLL_FIND_SENSOR,
@@ -49,5 +52,5 @@ public interface BiometricOverlayConstants {
REASON_AUTH_OTHER,
REASON_AUTH_SETTINGS})
@Retention(RetentionPolicy.SOURCE)
- @interface ShowReason {}
+ public @interface RequestReason {}
}
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 5bdbe2b573b2..8514f98fbf0d 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -16,6 +16,7 @@
package android.hardware.biometrics;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IInvalidationCallback;
@@ -66,6 +67,12 @@ interface IAuthService {
// Register callback for when keyguard biometric eligibility changes.
void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
+ // Register listener for changes to authentication state.
+ void registerAuthenticationStateListener(AuthenticationStateListener listener);
+
+ // Unregister listener for changes to authentication state.
+ void unregisterAuthenticationStateListener(AuthenticationStateListener listener);
+
// Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the
// specified user. This happens when enrollments have been added on devices with multiple
// biometric sensors.
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 8196bf505e02..20b09326e9c0 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -40,7 +40,6 @@ import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
-import android.util.FeatureFlagUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
@@ -722,6 +721,7 @@ public final class CameraExtensionCharacteristics {
switch(format) {
case ImageFormat.YUV_420_888:
case ImageFormat.JPEG:
+ case ImageFormat.JPEG_R:
break;
default:
throw new IllegalArgumentException("Unsupported format: " + format);
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 93fbe8aee8d4..7cf10d89004f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1216,7 +1216,7 @@ public abstract class CameraMetadata<TKey> {
* <ul>
* <li>Profile {@link android.hardware.camera2.params.DynamicRangeProfiles#HLG10 }</li>
* <li>All mandatory stream combinations for this specific capability as per
- * <a href="CameraDevice#10-bit-output-additional-guaranteed-configurations">documentation</a></li>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations">documentation</a></li>
* <li>In case the device is not able to capture some combination of supported
* standard 8-bit and/or 10-bit dynamic range profiles within the same capture request,
* then those constraints must be listed in
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 06397c9a1598..ded96a23e11e 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1484,7 +1484,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>To start a CaptureSession with a target FPS range different from the
* capture request template's default value, the application
* is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the target fps range before creating the capture session. The aeTargetFpsRange is
* typically a session parameter. Specifying it at session creation time helps avoid
* session reconfiguration delays in cases like 60fps or high speed recording.</p>
@@ -2161,7 +2161,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* OFF if the recording output is not stabilized, or if there are no output
* Surface types that can be stabilized.</p>
* <p>The application is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the desired video stabilization mode before creating the capture session.
* Video stabilization mode is a session parameter on many devices. Specifying
* it at session creation time helps avoid reconfiguration delay caused by difference
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ab4406c37c8e..1d26d69a58b9 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -899,7 +899,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>To start a CaptureSession with a target FPS range different from the
* capture request template's default value, the application
* is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the target fps range before creating the capture session. The aeTargetFpsRange is
* typically a session parameter. Specifying it at session creation time helps avoid
* session reconfiguration delays in cases like 60fps or high speed recording.</p>
@@ -2382,7 +2382,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* OFF if the recording output is not stabilized, or if there are no output
* Surface types that can be stabilized.</p>
* <p>The application is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the desired video stabilization mode before creating the capture session.
* Video stabilization mode is a session parameter on many devices. Specifying
* it at session creation time helps avoid reconfiguration delay caused by difference
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 935157a48a45..fe7de8333784 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -983,6 +983,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* @hide
*/
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 0100660669e9..f594c00b0e47 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -15,6 +15,7 @@
*/
package android.hardware.fingerprint;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricStateListener;
@@ -203,6 +204,14 @@ interface IFingerprintService {
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void setSidefpsController(in ISidefpsController controller);
+ // Registers AuthenticationStateListener.
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void registerAuthenticationStateListener(AuthenticationStateListener listener);
+
+ // Unregisters AuthenticationStateListener.
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void unregisterAuthenticationStateListener(AuthenticationStateListener listener);
+
// Registers BiometricStateListener.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerBiometricStateListener(IBiometricStateListener listener);
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 98a980f5e7f8..f407fb73534f 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -284,6 +284,20 @@ public final class NfcAdapter {
public static final int STATE_TURNING_OFF = 4;
/**
+ * Possible states from {@link #getAdapterState}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_OFF,
+ STATE_TURNING_ON,
+ STATE_ON,
+ STATE_TURNING_OFF
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AdapterState{}
+
+ /**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag enables polling for Nfc-A technology.
@@ -948,7 +962,7 @@ public final class NfcAdapter {
*/
@SystemApi
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public int getAdapterState() {
+ public @AdapterState int getAdapterState() {
try {
return sService.getState();
} catch (RemoteException e) {
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index e331c95288d9..bd087f970426 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -130,7 +130,7 @@ public final class ApduServiceInfo implements Parcelable {
/**
* State of the service for CATEGORY_OTHER selection
*/
- private boolean mOtherServiceEnabled;
+ private boolean mCategoryOtherServiceEnabled;
/**
* @hide
@@ -183,7 +183,7 @@ public final class ApduServiceInfo implements Parcelable {
this.mBannerResourceId = bannerResource;
this.mUid = uid;
this.mSettingsActivityName = settingsActivityName;
- this.mOtherServiceEnabled = isEnabled;
+ this.mCategoryOtherServiceEnabled = isEnabled;
}
@@ -374,7 +374,7 @@ public final class ApduServiceInfo implements Parcelable {
// Set uid
mUid = si.applicationInfo.uid;
- mOtherServiceEnabled = false; // support other category
+ mCategoryOtherServiceEnabled = false; // support other category
}
@@ -746,7 +746,7 @@ public final class ApduServiceInfo implements Parcelable {
dest.writeInt(mUid);
dest.writeString(mSettingsActivityName);
- dest.writeInt(mOtherServiceEnabled ? 1 : 0);
+ dest.writeInt(mCategoryOtherServiceEnabled ? 1 : 0);
};
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@@ -809,7 +809,7 @@ public final class ApduServiceInfo implements Parcelable {
pw.println(" Static AID groups:");
for (AidGroup group : mStaticAidGroups.values()) {
pw.println(" Category: " + group.getCategory()
- + "(enabled: " + mOtherServiceEnabled + ")");
+ + "(enabled: " + mCategoryOtherServiceEnabled + ")");
for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
@@ -817,7 +817,7 @@ public final class ApduServiceInfo implements Parcelable {
pw.println(" Dynamic AID groups:");
for (AidGroup group : mDynamicAidGroups.values()) {
pw.println(" Category: " + group.getCategory()
- + "(enabled: " + mOtherServiceEnabled + ")");
+ + "(enabled: " + mCategoryOtherServiceEnabled + ")");
for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
@@ -834,8 +834,8 @@ public final class ApduServiceInfo implements Parcelable {
* @param enabled true to indicate if user has enabled this service
*/
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public void setOtherServiceEnabled(boolean enabled) {
- mOtherServiceEnabled = enabled;
+ public void setCategoryOtherServiceEnabled(boolean enabled) {
+ mCategoryOtherServiceEnabled = enabled;
}
@@ -845,8 +845,8 @@ public final class ApduServiceInfo implements Parcelable {
* @return true to indicate if user has enabled this service
*/
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public boolean isOtherServiceEnabled() {
- return mOtherServiceEnabled;
+ public boolean isCategoryOtherServiceEnabled() {
+ return mCategoryOtherServiceEnabled;
}
/**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 16ffaef03121..10a8022df0ea 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1657,6 +1657,7 @@ public abstract class BatteryStats {
*/
public abstract CpuScalingPolicies getCpuScalingPolicies();
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public final static class HistoryTag {
public static final int HISTORY_TAG_POOL_OVERFLOW = -1;
@@ -1713,6 +1714,7 @@ public abstract class BatteryStats {
* Optional detailed information that can go into a history step. This is typically
* generated each time the battery level changes.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public final static class HistoryStepDetails {
// Time (in 1/100 second) spent in user space and the kernel since the last step.
public int userTime;
@@ -1797,6 +1799,7 @@ public abstract class BatteryStats {
/**
* An extension to the history item describing a proc state change for a UID.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static final class ProcessStateChange {
public int uid;
public @BatteryConsumer.ProcessState int processState;
@@ -1850,6 +1853,7 @@ public abstract class BatteryStats {
/**
* Battery history record.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static final class HistoryItem {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public HistoryItem next;
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 0ccc485a34f4..02e40cfbecaa 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -396,6 +396,7 @@ public class Binder implements IBinder {
* This is Test API which will be used to override output of isDirectlyHandlingTransactionNative
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public static void setIsDirectlyHandlingTransactionOverride(boolean isInTransaction) {
sIsHandlingBinderTransaction = isInTransaction;
}
@@ -1068,6 +1069,7 @@ public class Binder implements IBinder {
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public @Nullable String getTransactionName(int transactionCode) {
return null;
}
@@ -1076,6 +1078,7 @@ public class Binder implements IBinder {
* @hide
*/
@VisibleForTesting
+ @android.ravenwood.annotation.RavenwoodKeep
public final @Nullable String getTransactionTraceName(int transactionCode) {
final boolean isInterfaceUserDefined = getMaxTransactionId() == 0;
if (mTransactionTraceNames == null) {
@@ -1113,6 +1116,7 @@ public class Binder implements IBinder {
return transactionTraceName;
}
+ @android.ravenwood.annotation.RavenwoodKeep
private @NonNull String getSimpleDescriptor() {
String descriptor = mDescriptor;
if (descriptor == null) {
@@ -1132,6 +1136,7 @@ public class Binder implements IBinder {
* @return The highest user-defined transaction id of all transactions.
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public int getMaxTransactionId() {
return 0;
}
diff --git a/core/java/android/os/Broadcaster.java b/core/java/android/os/Broadcaster.java
index 88760b0b6828..17cf69296015 100644
--- a/core/java/android/os/Broadcaster.java
+++ b/core/java/android/os/Broadcaster.java
@@ -19,6 +19,7 @@ package android.os;
import android.compat.annotation.UnsupportedAppUsage;
/** @hide */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Broadcaster
{
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
diff --git a/core/java/android/os/BundleMerger.java b/core/java/android/os/BundleMerger.java
index 857aaf57f640..dc243a5e9c08 100644
--- a/core/java/android/os/BundleMerger.java
+++ b/core/java/android/os/BundleMerger.java
@@ -48,6 +48,7 @@ import java.util.function.BinaryOperator;
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BundleMerger implements Parcelable {
private static final String TAG = "BundleMerger";
diff --git a/core/java/android/os/ConditionVariable.java b/core/java/android/os/ConditionVariable.java
index a13eaa6f19bf..b5ed53bf0e5e 100644
--- a/core/java/android/os/ConditionVariable.java
+++ b/core/java/android/os/ConditionVariable.java
@@ -29,6 +29,7 @@ package android.os;
* This class uses itself as the object to wait on, so if you wait()
* or notify() on a ConditionVariable, the results are undefined.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ConditionVariable
{
private volatile boolean mCondition;
diff --git a/core/java/android/os/PackageTagsList.java b/core/java/android/os/PackageTagsList.java
index df99074a851f..cbc427207ccf 100644
--- a/core/java/android/os/PackageTagsList.java
+++ b/core/java/android/os/PackageTagsList.java
@@ -41,6 +41,7 @@ import java.util.Set;
*/
@TestApi
@Immutable
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class PackageTagsList implements Parcelable {
// an empty set value matches any attribution tag (ie, wildcard)
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index f2930fe45295..8e860c35388d 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -465,9 +465,7 @@ public final class Parcel {
private static native byte[] nativeMarshall(long nativePtr);
private static native void nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length);
- @RavenwoodThrow
private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
- @RavenwoodThrow
private static native boolean nativeCompareDataInRange(
long ptrA, int offsetA, long ptrB, int offsetB, int length);
private static native void nativeAppendFrom(
diff --git a/core/java/android/os/TimestampedValue.java b/core/java/android/os/TimestampedValue.java
index 3d8a5504b56d..e514d63aa147 100644
--- a/core/java/android/os/TimestampedValue.java
+++ b/core/java/android/os/TimestampedValue.java
@@ -35,6 +35,7 @@ import java.util.Objects;
* @param <T> the type of the value with an associated timestamp
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class TimestampedValue<T> implements Parcelable {
private final long mReferenceTimeMillis;
@Nullable
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index bc80c8b20b86..6d4e28403908 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -23,6 +23,7 @@ import java.util.Objects;
* Currently the public representation of what a work source is not
* defined; this is an opaque container.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class WorkSource implements Parcelable {
static final String TAG = "WorkSource";
static final boolean DEBUG = false;
@@ -141,11 +142,17 @@ public class WorkSource implements Parcelable {
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static boolean isChainedBatteryAttributionEnabled(Context context) {
return Settings.Global.getInt(context.getContentResolver(),
Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED, 0) == 1;
}
+ /** @hide */
+ public static boolean isChainedBatteryAttributionEnabled$ravenwood(Context context) {
+ return false;
+ }
+
/**
* Returns the number of uids in this work source.
* @hide
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 145981c92283..83d237d6e53b 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -78,6 +78,13 @@ flag {
}
flag {
+ name: "adpf_use_fmq_channel"
+ namespace: "game"
+ description: "Guards use of the FMQ channel for ADPF"
+ bug: "315894228"
+}
+
+flag {
name: "battery_service_support_current_adb_command"
namespace: "backstage_power"
description: "Whether or not BatteryService supports adb commands for Current values."
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index bf22dccce9d4..6941857e8fef 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -1,6 +1,6 @@
# Bug component: 95221
-# Please assign new bugs to android-storage-triage@, not to individual people
+# PLEASE ASSIGN NEW BUGS TO android-storage-triage@, NOT TO INDIVIDUAL PEOPLE
# Android Storage Team
alukin@google.com
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index 69d86a6604ad..437668c9a7de 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -44,3 +44,10 @@ flag {
description: "Enables the independent keyboard vibration settings feature"
bug: "289107579"
}
+
+flag {
+ namespace: "haptics"
+ name: "adaptive_haptics_enabled"
+ description: "Enables the adaptive haptics feature"
+ bug: "305961689"
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2ed994b503c9..2cc56d838b79 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8301,6 +8301,17 @@ public final class Settings {
public static final String ACCESSIBILITY_BUTTON_TARGETS = "accessibility_button_targets";
/**
+ * Setting specifying the accessibility services, accessibility shortcut targets,
+ * or features to be toggled via a tile in the quick settings panel.
+ *
+ * <p> This is a colon-separated string list which contains the flattened
+ * {@link ComponentName} and the class name of a system class implementing a supported
+ * accessibility feature.
+ * @hide
+ */
+ public static final String ACCESSIBILITY_QS_TARGETS = "accessibility_qs_targets";
+
+ /**
* The system class name of magnification controller which is a target to be toggled via
* accessibility shortcut or accessibility button.
*
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 0c4eedab2fc0..e679d201c58f 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -16,6 +16,8 @@
package android.security;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.security.net.config.ApplicationConfig;
@@ -26,9 +28,6 @@ import android.security.net.config.ManifestConfigSource;
*
* <p>Network stacks/components should honor this policy to make it possible to centrally control
* the relevant aspects of network security behavior.
- *
- * <p>The policy currently consists of a single flag: whether cleartext network traffic is
- * permitted. See {@link #isCleartextTrafficPermitted()}.
*/
public class NetworkSecurityPolicy {
@@ -94,6 +93,22 @@ public class NetworkSecurityPolicy {
}
/**
+ * Returns {@code true} if Certificate Transparency information is required to be verified by
+ * the client in TLS connections to {@code hostname}.
+ *
+ * <p>See RFC6962 section 3.3 for more details.
+ *
+ * @param hostname hostname to check whether certificate transparency verification is required
+ * @return {@code true} if certificate transparency verification is required and {@code false}
+ * otherwise
+ */
+ @FlaggedApi(Flags.FLAG_CERTIFICATE_TRANSPARENCY_CONFIGURATION)
+ public boolean isCertificateTransparencyVerificationRequired(@NonNull String hostname) {
+ return libcore.net.NetworkSecurityPolicy.getInstance()
+ .isCertificateTransparencyVerificationRequired(hostname);
+ }
+
+ /**
* Handle an update to the system or user certificate stores.
* @hide
*/
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 28ef70b14026..b56bef3c93a0 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -1,6 +1,13 @@
package: "android.security"
flag {
+ name: "certificate_transparency_configuration"
+ namespace: "network_security"
+ description: "Enable certificate transparency setting in the network security config"
+ bug: "28746284"
+}
+
+flag {
name: "fsverity_api"
namespace: "hardware_backed_security"
description: "Feature flag for fs-verity API"
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 801ecebc616f..4cc870bfb47a 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -16,10 +16,15 @@
package android.security.net.config;
+import static android.security.Flags.certificateTransparencyConfiguration;
+
+import android.annotation.NonNull;
import android.util.Pair;
+
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
+
import javax.net.ssl.X509TrustManager;
/**
@@ -147,6 +152,22 @@ public final class ApplicationConfig {
return getConfigForHostname(hostname).isCleartextTrafficPermitted();
}
+ /**
+ * Returns {@code true} if Certificate Transparency information is required to be verified by
+ * the client in TLS connections to {@code hostname}.
+ *
+ * <p>See RFC6962 section 3.3 for more details.
+ *
+ * @param hostname hostname to check whether certificate transparency verification is required
+ * @return {@code true} if certificate transparency verification is required and {@code false}
+ * otherwise
+ */
+ public boolean isCertificateTransparencyVerificationRequired(@NonNull String hostname) {
+ return certificateTransparencyConfiguration()
+ ? getConfigForHostname(hostname).isCertificateTransparencyVerificationRequired()
+ : NetworkSecurityConfig.DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED;
+ }
+
public void handleTrustStorageUpdate() {
synchronized(mLock) {
// If the config is uninitialized then there is no work to be done to handle an update,
diff --git a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
index a708f5b57dc9..801b32b055aa 100644
--- a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
+++ b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
@@ -40,6 +40,6 @@ public class ConfigNetworkSecurityPolicy extends libcore.net.NetworkSecurityPoli
@Override
public boolean isCertificateTransparencyVerificationRequired(String hostname) {
- return false;
+ return mConfig.isCertificateTransparencyVerificationRequired(hostname);
}
}
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 00872fb3b62d..129ae63ec9c0 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -38,9 +38,12 @@ public final class NetworkSecurityConfig {
public static final boolean DEFAULT_CLEARTEXT_TRAFFIC_PERMITTED = true;
/** @hide */
public static final boolean DEFAULT_HSTS_ENFORCED = false;
+ /** @hide */
+ public static final boolean DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED = false;
private final boolean mCleartextTrafficPermitted;
private final boolean mHstsEnforced;
+ private final boolean mCertificateTransparencyVerificationRequired;
private final PinSet mPins;
private final List<CertificatesEntryRef> mCertificatesEntryRefs;
private Set<TrustAnchor> mAnchors;
@@ -48,10 +51,15 @@ public final class NetworkSecurityConfig {
private NetworkSecurityTrustManager mTrustManager;
private final Object mTrustManagerLock = new Object();
- private NetworkSecurityConfig(boolean cleartextTrafficPermitted, boolean hstsEnforced,
- PinSet pins, List<CertificatesEntryRef> certificatesEntryRefs) {
+ private NetworkSecurityConfig(
+ boolean cleartextTrafficPermitted,
+ boolean hstsEnforced,
+ boolean certificateTransparencyVerificationRequired,
+ PinSet pins,
+ List<CertificatesEntryRef> certificatesEntryRefs) {
mCleartextTrafficPermitted = cleartextTrafficPermitted;
mHstsEnforced = hstsEnforced;
+ mCertificateTransparencyVerificationRequired = certificateTransparencyVerificationRequired;
mPins = pins;
mCertificatesEntryRefs = certificatesEntryRefs;
// Sort the certificates entry refs so that all entries that override pins come before
@@ -104,6 +112,11 @@ public final class NetworkSecurityConfig {
return mHstsEnforced;
}
+ // TODO(b/28746284): add exceptions for user-added certificates and enterprise overrides.
+ public boolean isCertificateTransparencyVerificationRequired() {
+ return mCertificateTransparencyVerificationRequired;
+ }
+
public PinSet getPins() {
return mPins;
}
@@ -208,6 +221,9 @@ public final class NetworkSecurityConfig {
private boolean mHstsEnforced = DEFAULT_HSTS_ENFORCED;
private boolean mCleartextTrafficPermittedSet = false;
private boolean mHstsEnforcedSet = false;
+ private boolean mCertificateTransparencyVerificationRequired =
+ DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED;
+ private boolean mCertificateTransparencyVerificationRequiredSet = false;
private Builder mParentBuilder;
/**
@@ -313,12 +329,35 @@ public final class NetworkSecurityConfig {
return mCertificatesEntryRefs;
}
+ Builder setCertificateTransparencyVerificationRequired(boolean required) {
+ mCertificateTransparencyVerificationRequired = required;
+ mCertificateTransparencyVerificationRequiredSet = true;
+ return this;
+ }
+
+ private boolean getCertificateTransparencyVerificationRequired() {
+ if (mCertificateTransparencyVerificationRequiredSet) {
+ return mCertificateTransparencyVerificationRequired;
+ }
+ if (mParentBuilder != null) {
+ return mParentBuilder.getCertificateTransparencyVerificationRequired();
+ }
+ return DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED;
+ }
+
public NetworkSecurityConfig build() {
boolean cleartextPermitted = getEffectiveCleartextTrafficPermitted();
boolean hstsEnforced = getEffectiveHstsEnforced();
+ boolean certificateTransparencyVerificationRequired =
+ getCertificateTransparencyVerificationRequired();
PinSet pinSet = getEffectivePinSet();
List<CertificatesEntryRef> entryRefs = getEffectiveCertificatesEntryRefs();
- return new NetworkSecurityConfig(cleartextPermitted, hstsEnforced, pinSet, entryRefs);
+ return new NetworkSecurityConfig(
+ cleartextPermitted,
+ hstsEnforced,
+ certificateTransparencyVerificationRequired,
+ pinSet,
+ entryRefs);
}
}
}
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index 311a8d23b964..b1c14793bbbd 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -171,6 +171,11 @@ public class XmlConfigSource implements ConfigSource {
return new Domain(domain, includeSubdomains);
}
+ private boolean parseCertificateTransparency(XmlResourceParser parser)
+ throws IOException, XmlPullParserException, ParserException {
+ return parser.getAttributeBooleanValue(null, "enabled", false);
+ }
+
private CertificatesEntryRef parseCertificatesEntry(XmlResourceParser parser,
boolean defaultOverridePins)
throws IOException, XmlPullParserException, ParserException {
@@ -226,7 +231,6 @@ public class XmlConfigSource implements ConfigSource {
boolean seenPinSet = false;
boolean seenTrustAnchors = false;
boolean defaultOverridePins = configType == CONFIG_DEBUG;
- String configName = parser.getName();
int outerDepth = parser.getDepth();
// Add this builder now so that this builder occurs before any of its children. This
// makes the final build pass easier.
@@ -279,6 +283,15 @@ public class XmlConfigSource implements ConfigSource {
"Nested domain-config not allowed in " + getConfigString(configType));
}
builders.addAll(parseConfigEntry(parser, seenDomains, builder, configType));
+ } else if ("certificateTransparency".equals(tagName)) {
+ if (configType != CONFIG_BASE && configType != CONFIG_DOMAIN) {
+ throw new ParserException(
+ parser,
+ "certificateTransparency not allowed in "
+ + getConfigString(configType));
+ }
+ builder.setCertificateTransparencyVerificationRequired(
+ parseCertificateTransparency(parser));
} else {
XmlUtils.skipCurrentTag(parser);
}
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 531626b1e85f..6e771f8f0ffe 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
package android.service.notification;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -117,7 +119,7 @@ public final class Condition implements Parcelable {
/** The source of, or reason for, the state change represented by this Condition. **/
@FlaggedApi(Flags.FLAG_MODES_API)
- public final @Source int source;
+ public final @Source int source; // default = SOURCE_UNKNOWN
/**
* The maximum string length for any string contained in this condition.
@@ -179,7 +181,7 @@ public final class Condition implements Parcelable {
this.line2 = getTrimmedString(line2);
this.icon = icon;
this.state = state;
- this.source = source;
+ this.source = checkValidSource(source);
this.flags = flags;
}
@@ -197,10 +199,26 @@ public final class Condition implements Parcelable {
source.readInt());
}
+ /** @hide */
+ public void validate() {
+ if (Flags.modesApi()) {
+ checkValidSource(source);
+ }
+ }
+
private static boolean isValidState(int state) {
return state >= STATE_FALSE && state <= STATE_ERROR;
}
+ private static int checkValidSource(@Source int source) {
+ if (Flags.modesApi()) {
+ checkArgument(source >= SOURCE_UNKNOWN && source <= SOURCE_CONTEXT,
+ "Condition source must be one of SOURCE_UNKNOWN, SOURCE_USER_ACTION, "
+ + "SOURCE_SCHEDULE, or SOURCE_CONTEXT");
+ }
+ return source;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(id, 0);
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index a5b087c05dfa..fcdc5fe71e4e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1980,6 +1980,7 @@ public class ZenModeConfig implements Parcelable {
@Nullable public ZenDeviceEffects zenDeviceEffects;
public boolean modified; // rule has been modified from initial creation
public String pkg;
+ @AutomaticZenRule.Type
public int type = AutomaticZenRule.TYPE_UNKNOWN;
public String triggerDescription;
public String iconResName;
diff --git a/core/java/android/service/persistentdata/OWNERS b/core/java/android/service/persistentdata/OWNERS
new file mode 100644
index 000000000000..6dfb888dedad
--- /dev/null
+++ b/core/java/android/service/persistentdata/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pdb/OWNERS
diff --git a/core/java/android/service/voice/HotwordRejectedResult.java b/core/java/android/service/voice/HotwordRejectedResult.java
index 26c1ca428c3b..eb1ac67719ed 100644
--- a/core/java/android/service/voice/HotwordRejectedResult.java
+++ b/core/java/android/service/voice/HotwordRejectedResult.java
@@ -16,9 +16,11 @@
package android.service.voice;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcelable;
+import android.service.voice.flags.Flags;
import com.android.internal.util.DataClass;
@@ -53,12 +55,17 @@ public final class HotwordRejectedResult implements Parcelable {
/** High confidence in hotword detector result. */
public static final int CONFIDENCE_LEVEL_HIGH = 3;
+ /** Very high confidence in hotword detector result. **/
+ @FlaggedApi(Flags.FLAG_ALLOW_HOTWORD_BUMP_EGRESS)
+ public static final int CONFIDENCE_LEVEL_VERY_HIGH = 4;
+
/** @hide */
@IntDef(prefix = {"CONFIDENCE_LEVEL_"}, value = {
CONFIDENCE_LEVEL_NONE,
CONFIDENCE_LEVEL_LOW,
CONFIDENCE_LEVEL_MEDIUM,
- CONFIDENCE_LEVEL_HIGH
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
})
@Retention(RetentionPolicy.SOURCE)
@interface HotwordConfidenceLevelValue {
@@ -91,9 +98,10 @@ public final class HotwordRejectedResult implements Parcelable {
CONFIDENCE_LEVEL_NONE,
CONFIDENCE_LEVEL_LOW,
CONFIDENCE_LEVEL_MEDIUM,
- CONFIDENCE_LEVEL_HIGH
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
})
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
public @interface ConfidenceLevel {}
@@ -109,6 +117,8 @@ public final class HotwordRejectedResult implements Parcelable {
return "CONFIDENCE_LEVEL_MEDIUM";
case CONFIDENCE_LEVEL_HIGH:
return "CONFIDENCE_LEVEL_HIGH";
+ case CONFIDENCE_LEVEL_VERY_HIGH:
+ return "CONFIDENCE_LEVEL_VERY_HIGH";
default: return Integer.toHexString(value);
}
}
@@ -259,10 +269,10 @@ public final class HotwordRejectedResult implements Parcelable {
}
@DataClass.Generated(
- time = 1621961370106L,
+ time = 1701990933632L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordRejectedResult.java",
- inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_HIGH\nprivate final @android.service.voice.HotwordRejectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final @android.annotation.FlaggedApi int CONFIDENCE_LEVEL_VERY_HIGH\nprivate final @android.service.voice.HotwordRejectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index fba09233e4f4..75ab48a43da6 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -1042,13 +1042,13 @@ public class VoiceInteractionService extends Service {
@SystemApi
@FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
@RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
- public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
- Log.i(TAG, "setIsReceiveSandboxedTrainingDataAllowed to " + allowed);
+ public void setShouldReceiveSandboxedTrainingData(boolean allowed) {
+ Log.i(TAG, "setShouldReceiveSandboxedTrainingData to " + allowed);
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}
try {
- mSystemService.setIsReceiveSandboxedTrainingDataAllowed(allowed);
+ mSystemService.setShouldReceiveSandboxedTrainingData(allowed);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
index c414ef8a6826..b596666bf607 100644
--- a/core/java/android/service/voice/flags/flags.aconfig
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -6,3 +6,10 @@ flag {
description: "This flag allows the hotword detection service to egress training data to the default assistant."
bug: "296074924"
}
+
+flag {
+ name: "allow_hotword_bump_egress"
+ namespace: "machine_learning"
+ description: "This flag allows hotword detection service to egress reason code for hotword bump."
+ bug: "290951024"
+}
diff --git a/core/java/android/view/ISurfaceControlViewHostParent.aidl b/core/java/android/view/ISurfaceControlViewHostParent.aidl
index f42e00148587..559c20ee4825 100644
--- a/core/java/android/view/ISurfaceControlViewHostParent.aidl
+++ b/core/java/android/view/ISurfaceControlViewHostParent.aidl
@@ -16,6 +16,7 @@
package android.view;
+import android.view.KeyEvent;
import android.view.WindowManager;
/**
@@ -24,4 +25,6 @@ import android.view.WindowManager;
*/
oneway interface ISurfaceControlViewHostParent {
void updateParams(in WindowManager.LayoutParams[] childAttrs);
+ // To forward the back key event from embedded to host app.
+ void forwardBackKeyToParent(in KeyEvent keyEvent);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index dbacca5def51..9bf43a390d70 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -162,6 +162,8 @@ interface IWindowSession {
* @param flags See {@code View#startDragAndDrop}
* @param surface Surface containing drag shadow image
* @param touchSource See {@code InputDevice#getSource()}
+ * @param touchDeviceId device ID of last touch event
+ * @param pointerId pointer ID of last touch event
* @param touchX X coordinate of last touch point
* @param touchY Y coordinate of last touch point
* @param thumbCenterX X coordinate for the position within the shadow image that should be
@@ -171,9 +173,9 @@ interface IWindowSession {
* @param data Data transferred by drag and drop
* @return Token of drag operation which will be passed to cancelDragAndDrop.
*/
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
- float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
+ int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
+ float thumbCenterY, in ClipData data);
/**
* Drops the content of the current drag operation for accessibility
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 405653123f79..4840f003da3e 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -447,6 +447,7 @@ public class SurfaceControlViewHost {
addWindowToken(attrs);
view.setLayoutParams(attrs);
mViewRoot.setView(view, attrs, null);
+ mViewRoot.setBackKeyCallbackForWindowlessWindow(mWm::forwardBackKeyToParent);
}
/**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a44a95a1677f..108de281a411 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -37,6 +37,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RenderNode;
+import android.hardware.input.InputManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -159,6 +160,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private static final boolean DEBUG = false;
private static final boolean DEBUG_POSITION = false;
+ private static final long FORWARD_BACK_KEY_TOLERANCE_MS = 100;
+
@UnsupportedAppUsage(
maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
publicAlternatives = "Track {@link SurfaceHolder#addCallback} instead")
@@ -326,6 +329,41 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
});
}
}
+
+ @Override
+ public void forwardBackKeyToParent(@NonNull KeyEvent keyEvent) {
+ runOnUiThread(() -> {
+ if (!isAttachedToWindow() || keyEvent.getKeyCode() != KeyEvent.KEYCODE_BACK) {
+ return;
+ }
+ final ViewRootImpl vri = getViewRootImpl();
+ if (vri == null) {
+ return;
+ }
+ final InputManager inputManager = mContext.getSystemService(InputManager.class);
+ if (inputManager == null) {
+ return;
+ }
+ // Check that the event was created recently.
+ final long timeDiff = SystemClock.uptimeMillis() - keyEvent.getEventTime();
+ if (timeDiff > FORWARD_BACK_KEY_TOLERANCE_MS) {
+ Log.e(TAG, "Ignore the input event that exceed the tolerance time, "
+ + "exceed " + timeDiff + "ms");
+ return;
+ }
+ if (inputManager.verifyInputEvent(keyEvent) == null) {
+ Log.e(TAG, "Received invalid input event");
+ return;
+ }
+ try {
+ vri.processingBackKey(true);
+ vri.enqueueInputEvent(keyEvent, null /* receiver */, 0 /* flags */,
+ true /* processImmediately */);
+ } finally {
+ vri.processingBackKey(false);
+ }
+ });
+ }
};
private final boolean mRtDrivenClipping = Flags.clipSurfaceviews();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 75f8eba01fa2..bb5ee0359b6b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28340,6 +28340,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
IBinder token = mAttachInfo.mSession.performDrag(
mAttachInfo.mWindow, flags, null,
mAttachInfo.mViewRootImpl.getLastTouchSource(),
+ mAttachInfo.mViewRootImpl.getLastTouchDeviceId(),
+ mAttachInfo.mViewRootImpl.getLastTouchPointerId(),
0f, 0f, 0f, 0f, data);
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token);
@@ -28414,7 +28416,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl,
- root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y,
+ root.getLastTouchSource(), root.getLastTouchDeviceId(),
+ root.getLastTouchPointerId(), lastTouchPoint.x, lastTouchPoint.y,
shadowTouchPoint.x, shadowTouchPoint.y, data);
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5cbb42e0e346..e83488e2689e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -76,13 +76,8 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_E
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -96,6 +91,7 @@ import static android.view.accessibility.Flags.reduceWindowContentChangedEventTh
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
+import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
import static com.android.input.flags.Flags.enablePointerChoreographer;
@@ -255,7 +251,7 @@ import java.util.OptionalInt;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -375,6 +371,8 @@ public final class ViewRootImpl implements ViewParent,
*/
private static final int KEEP_CLEAR_AREA_REPORT_RATE_MILLIS = 100;
+ private static final long NANOS_PER_SEC = 1000000000;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
@@ -620,6 +618,13 @@ public final class ViewRootImpl implements ViewParent,
boolean mUpcomingWindowFocus;
@GuardedBy("this")
boolean mUpcomingInTouchMode;
+ // While set, allow this VRI to handle back key without drop it.
+ private boolean mProcessingBackKey;
+ /**
+ * Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back
+ * key event host app.
+ */
+ private Predicate<KeyEvent> mWindowlessBackKeyCallback;
public boolean mTraversalScheduled;
int mTraversalBarrier;
@@ -808,6 +813,8 @@ public final class ViewRootImpl implements ViewParent,
final PointF mDragPoint = new PointF();
final PointF mLastTouchPoint = new PointF();
int mLastTouchSource;
+ int mLastTouchDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
+ int mLastTouchPointerId;
/** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/
private int mLastClickToolType;
@@ -822,6 +829,8 @@ public final class ViewRootImpl implements ViewParent,
private boolean mInsetsAnimationRunning;
+ private long mPreviousFrameDrawnTime = -1;
+
/**
* The resolved pointer icon type requested by this window.
* A null value indicates the resolved pointer icon has not yet been calculated.
@@ -1059,11 +1068,14 @@ public final class ViewRootImpl implements ViewParent,
private boolean mChildBoundingInsetsChanged = false;
private String mTag = TAG;
+ private String mFpsTraceName;
private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
+ private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
static {
sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
+ sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision();
}
// The latest input event from the gesture that was used to resolve the pointer icon.
@@ -1307,6 +1319,7 @@ public final class ViewRootImpl implements ViewParent,
attrs = mWindowAttributes;
setTag();
+ mFpsTraceName = "FPS of " + getTitle();
if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
& WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
@@ -3194,7 +3207,11 @@ public final class ViewRootImpl implements ViewParent,
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
dispatchApplyInsets(host);
- if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
+ if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()
+ // Don't register compat OnBackInvokedCallback for windowless window.
+ // The onBackInvoked event by default should forward to host app, so the
+ // host app can decide the behavior.
+ && mWindowlessBackKeyCallback == null) {
// For apps requesting legacy back behavior, we add a compat callback that
// dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
// This way from system point of view, these apps are providing custom
@@ -4726,6 +4743,31 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ /**
+ * Called from draw() to collect metrics for frame rate decision.
+ */
+ private void collectFrameRateDecisionMetrics() {
+ if (!Trace.isEnabled()) {
+ if (mPreviousFrameDrawnTime > 0) mPreviousFrameDrawnTime = -1;
+ return;
+ }
+
+ if (mPreviousFrameDrawnTime < 0) {
+ mPreviousFrameDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
+ return;
+ }
+
+ long expectedDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
+ long timeDiff = expectedDrawnTime - mPreviousFrameDrawnTime;
+ if (timeDiff <= 0) {
+ return;
+ }
+
+ long fps = NANOS_PER_SEC / timeDiff;
+ Trace.setCounter(mFpsTraceName, fps);
+ mPreviousFrameDrawnTime = expectedDrawnTime;
+ }
+
private void reportDrawFinished(@Nullable Transaction t, int seqId) {
if (DEBUG_BLAST) {
Log.d(mTag, "reportDrawFinished");
@@ -5044,6 +5086,9 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_FPS) {
trackFPS();
}
+ if (sToolkitMetricsForFrameRateDecisionFlagValue) {
+ collectFrameRateDecisionMetrics();
+ }
if (!sFirstDrawComplete) {
synchronized (sFirstDrawHandlers) {
@@ -6660,7 +6705,8 @@ public final class ViewRootImpl implements ViewParent,
// Find a reason for dropping or canceling the event.
final String reason;
- if (!mAttachInfo.mHasWindowFocus
+ // The embedded window is focused, allow this VRI to handle back key.
+ if (!mAttachInfo.mHasWindowFocus && !(mProcessingBackKey && isBack(q.mEvent))
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
&& !isAutofillUiShowing()) {
// This is a non-pointer event and the window doesn't currently have input focus
@@ -6883,10 +6929,20 @@ public final class ViewRootImpl implements ViewParent,
// If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
// view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
- if (isBack(keyEvent)
- && mContext != null
- && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
- return doOnBackKeyEvent(keyEvent);
+ if (isBack(keyEvent)) {
+ if (mWindowlessBackKeyCallback != null) {
+ if (mWindowlessBackKeyCallback.test(keyEvent)) {
+ return keyEvent.getAction() == KeyEvent.ACTION_UP
+ && !keyEvent.isCanceled()
+ ? FINISH_HANDLED : FINISH_NOT_HANDLED;
+ } else {
+ // Unable to forward the back key to host, forward to next stage.
+ return FORWARD;
+ }
+ } else if (mContext != null
+ && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
+ return doOnBackKeyEvent(keyEvent);
+ }
}
if (mInputQueue != null) {
@@ -7109,6 +7165,8 @@ public final class ViewRootImpl implements ViewParent,
mLastTouchPoint.x = event.getRawX();
mLastTouchPoint.y = event.getRawY();
mLastTouchSource = event.getSource();
+ mLastTouchDeviceId = event.getDeviceId();
+ mLastTouchPointerId = event.getPointerId(0);
// Register last ACTION_UP. This will be propagated to IME.
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
@@ -8520,6 +8578,14 @@ public final class ViewRootImpl implements ViewParent,
return mLastTouchSource;
}
+ public int getLastTouchDeviceId() {
+ return mLastTouchDeviceId;
+ }
+
+ public int getLastTouchPointerId() {
+ return mLastTouchPointerId;
+ }
+
/**
* Used by InputMethodManager.
* @hide
@@ -10529,6 +10595,11 @@ public final class ViewRootImpl implements ViewParent,
mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget();
}
+ // Make this VRI able to process back key without drop it.
+ void processingBackKey(boolean processing) {
+ mProcessingBackKey = processing;
+ }
+
/**
* Collect and include any ScrollCaptureCallback instances registered with the window.
*
@@ -11753,13 +11824,18 @@ public final class ViewRootImpl implements ViewParent,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- enqueueInputEvent(ev);
+ enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */);
}
private void registerCompatOnBackInvokedCallback() {
mCompatOnBackInvokedCallback = () -> {
- sendBackKeyEvent(KeyEvent.ACTION_DOWN);
- sendBackKeyEvent(KeyEvent.ACTION_UP);
+ try {
+ processingBackKey(true);
+ sendBackKeyEvent(KeyEvent.ACTION_DOWN);
+ sendBackKeyEvent(KeyEvent.ACTION_UP);
+ } finally {
+ processingBackKey(false);
+ }
};
if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
@@ -12097,11 +12173,9 @@ public final class ViewRootImpl implements ViewParent,
boolean desiredAction = motionEventAction == MotionEvent.ACTION_DOWN
|| motionEventAction == MotionEvent.ACTION_MOVE
|| motionEventAction == MotionEvent.ACTION_UP;
- boolean desiredType = windowType == TYPE_BASE_APPLICATION || windowType == TYPE_APPLICATION
- || windowType == TYPE_APPLICATION_STARTING || windowType == TYPE_DRAWN_APPLICATION
- || windowType == TYPE_NOTIFICATION_SHADE || windowType == TYPE_STATUS_BAR;
+ boolean undesiredType = windowType == TYPE_INPUT_METHOD;
// use toolkitSetFrameRate flag to gate the change
- return desiredAction && desiredType && sToolkitSetFrameRateReadOnlyFlagValue;
+ return desiredAction && !undesiredType && sToolkitSetFrameRateReadOnlyFlagValue;
}
/**
@@ -12196,4 +12270,13 @@ public final class ViewRootImpl implements ViewParent,
}
return false;
}
+
+ /**
+ * Set the default back key callback for windowless window, to forward the back key event
+ * to host app.
+ * MUST NOT call this method for normal window.
+ */
+ void setBackKeyCallbackForWindowlessWindow(@NonNull Predicate<KeyEvent> callback) {
+ mWindowlessBackKeyCallback = callback;
+ }
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index c9526fde27df..3b444c44c368 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -75,7 +75,7 @@ public final class ViewTreeObserver {
private boolean mWindowShown;
// The reason that the last call to dispatchOnPreDraw() returned true to cancel and redraw
- private String mLastDispatchOnPreDrawCanceledReason;
+ private StringBuilder mLastDispatchOnPreDrawCanceledReason;
private boolean mAlive = true;
@@ -1173,9 +1173,15 @@ public final class ViewTreeObserver {
int count = access.size();
for (int i = 0; i < count; i++) {
final OnPreDrawListener preDrawListener = access.get(i);
- cancelDraw |= !(preDrawListener.onPreDraw());
- if (cancelDraw) {
- mLastDispatchOnPreDrawCanceledReason = preDrawListener.getClass().getName();
+ final boolean listenerCanceledDraw = !(preDrawListener.onPreDraw());
+ cancelDraw |= listenerCanceledDraw;
+ if (listenerCanceledDraw) {
+ final String className = preDrawListener.getClass().getName();
+ if (mLastDispatchOnPreDrawCanceledReason == null) {
+ mLastDispatchOnPreDrawCanceledReason = new StringBuilder(className);
+ } else {
+ mLastDispatchOnPreDrawCanceledReason.append("|").append(className);
+ }
}
}
} finally {
@@ -1191,7 +1197,10 @@ public final class ViewTreeObserver {
* @hide
*/
final String getLastDispatchOnPreDrawCanceledReason() {
- return mLastDispatchOnPreDrawCanceledReason;
+ if (mLastDispatchOnPreDrawCanceledReason != null) {
+ return mLastDispatchOnPreDrawCanceledReason.toString();
+ }
+ return null;
}
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c7e180732fd4..e3d9c605ff63 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -592,6 +592,13 @@ public interface WindowManager extends ViewManager {
int TRANSIT_FLAG_KEYGUARD_UNOCCLUDING = (1 << 13); // 0x2000
/**
+ * Transition flag: Indicates that there is a physical display switch
+ * TODO(b/316112906) remove after defer_display_updates flag roll out
+ * @hide
+ */
+ int TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH = (1 << 14); // 0x4000
+
+ /**
* @hide
*/
@IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
@@ -608,7 +615,8 @@ public interface WindowManager extends ViewManager {
TRANSIT_FLAG_INVISIBLE,
TRANSIT_FLAG_KEYGUARD_APPEARING,
TRANSIT_FLAG_KEYGUARD_OCCLUDING,
- TRANSIT_FLAG_KEYGUARD_UNOCCLUDING
+ TRANSIT_FLAG_KEYGUARD_UNOCCLUDING,
+ TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH,
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionFlags {}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index d817e6f51f55..d6ac56239aed 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
@@ -488,8 +489,9 @@ public class WindowlessWindowManager implements IWindowSession {
@Override
public android.os.IBinder performDrag(android.view.IWindow window, int flags,
- android.view.SurfaceControl surface, int touchSource, float touchX, float touchY,
- float thumbCenterX, float thumbCenterY, android.content.ClipData data) {
+ android.view.SurfaceControl surface, int touchSource, int touchDeviceId,
+ int touchPointerId, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ android.content.ClipData data) {
return null;
}
@@ -703,4 +705,17 @@ public class WindowlessWindowManager implements IWindowSession {
}
}
}
+
+ boolean forwardBackKeyToParent(@NonNull KeyEvent keyEvent) {
+ if (mParentInterface == null) {
+ return false;
+ }
+ try {
+ mParentInterface.forwardBackKeyToParent(keyEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to forward back key To Parent: ", e);
+ return false;
+ }
+ return true;
+ }
}
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index e057660961f6..0cc19fb70fbc 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -59,6 +59,13 @@ flag {
}
flag {
+ name: "motion_event_observing"
+ namespace: "accessibility"
+ description: "Allows accessibility services to intercept but not consume motion events from specified sources."
+ bug: "297595990"
+}
+
+flag {
namespace: "accessibility"
name: "granular_scrolling"
description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6bc2a1368a91..bb49679453ac 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -38,6 +38,7 @@ import android.annotation.RequiresFeature;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.ActivityOptions;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.ViewNodeBuilder;
import android.app.assist.AssistStructure.ViewNodeParcelable;
@@ -4370,7 +4371,11 @@ public final class AutofillManager {
if (afm != null) {
afm.post(() -> {
try {
- afm.mContext.startIntentSender(intentSender, intent, 0, 0, 0);
+ Bundle options = ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ .toBundle();
+ afm.mContext.startIntentSender(intentSender, intent, 0, 0, 0, options);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "startIntentSender() failed for intent:" + intentSender, e);
}
diff --git a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
index f3dc33cd2cc9..2a3008a53635 100644
--- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
+++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
@@ -27,3 +27,10 @@ flag {
description: "If true, an appop is logged on creation of accessibility overlays."
bug: "289081465"
}
+
+flag {
+ name: "rapid_clear_notifications_by_listener_app_op_enabled"
+ namespace: "content_protection"
+ description: "If true, an appop is logged when a notification is rapidly cleared by a notification listener."
+ bug: "289080543"
+}
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index a467afe5d06a..0aa516e08697 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -42,4 +42,12 @@ flag {
namespace: "core_graphics"
description: "Enable the `setFrameRate` callback"
bug: "299946220"
+}
+
+flag {
+ name: "toolkit_metrics_for_frame_rate_decision"
+ namespace: "toolkit"
+ description: "Feature flag for toolkit metrics collecting for frame rate decision"
+ bug: "301343249"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index da3134856731..8ad10af7250a 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,6 +16,7 @@
package android.widget;
+import static android.appwidget.flags.Flags.remoteAdapterConversion;
import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR;
import android.annotation.AttrRes;
@@ -36,7 +37,6 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.ActivityThread;
-import android.app.AppGlobals;
import android.app.Application;
import android.app.LoadedApk;
import android.app.PendingIntent;
@@ -108,7 +108,6 @@ import android.widget.AdapterView.OnItemClickListener;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.android.internal.R;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -4950,21 +4949,11 @@ public class RemoteViews implements Parcelable, Filter {
*/
@Deprecated
public void setRemoteAdapter(@IdRes int viewId, Intent intent) {
- if (isAdapterConversionEnabled()) {
+ if (remoteAdapterConversion()) {
addAction(new SetRemoteCollectionItemListAdapterAction(viewId, intent));
- return;
+ } else {
+ addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
}
- addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
- }
-
- /**
- * @hide
- * @return True if the remote adapter conversion is enabled
- */
- public static boolean isAdapterConversionEnabled() {
- return AppGlobals.getIntCoreSetting(
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT ? 1 : 0) != 0;
}
/**
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 7f65c52d01b8..07beb114898d 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -16,7 +16,7 @@ flag {
flag {
name: "defer_display_updates"
- namespace: "window_manager"
+ namespace: "windowing_frontend"
description: "Feature flag for deferring DisplayManager updates to WindowManager if Shell transition is running"
bug: "259220649"
is_fixed_read_only: true
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 7d06e3f5a7bc..2e80b7e19516 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -262,6 +262,11 @@ public class AccessibilityShortcutChooserActivity extends Activity {
return mMenuDialog;
}
+ @VisibleForTesting
+ public Dialog getPermissionDialog() {
+ return mPermissionDialog;
+ }
+
private AlertDialog createMenuDialog() {
final String dialogTitle =
getString(R.string.accessibility_select_shortcut_menu_title);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 82ee8fc47571..e92c6a6c4b34 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -397,5 +397,5 @@ interface IVoiceInteractionManagerService {
* sandboxed detection (from trusted process).
*/
@EnforcePermission("MANAGE_HOTWORD_DETECTION")
- void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed);
+ void setShouldReceiveSandboxedTrainingData(boolean allowed);
}
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index efc1455ecd45..f1aa330f562c 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -39,6 +39,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -308,7 +309,8 @@ public class SuspendedAppActivity extends AlertActivity
try {
final String[] errored = ipm.setPackagesSuspendedAsUser(
new String[]{mSuspendedPackage}, false, null, null, null, 0,
- mSuspendingPackage, mUserId);
+ mSuspendingPackage, mUserId /* suspendingUserId */,
+ mUserId /* targetUserId */);
if (ArrayUtils.contains(errored, mSuspendedPackage)) {
Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage);
break;
@@ -350,17 +352,18 @@ public class SuspendedAppActivity extends AlertActivity
}
public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
- String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
+ UserPackage suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
IntentSender onUnsuspend, int userId) {
- return new Intent()
+ Intent intent = new Intent()
.setClassName("android", SuspendedAppActivity.class.getName())
.putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
.putExtra(EXTRA_DIALOG_INFO, dialogInfo)
- .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
+ .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage.packageName)
.putExtra(EXTRA_UNSUSPEND_INTENT, onUnsuspend)
.putExtra(EXTRA_ACTIVITY_OPTIONS, options)
.putExtra(Intent.EXTRA_USER_ID, userId)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ return intent;
}
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index e494346bae5c..bd806bfb3e24 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -519,24 +519,6 @@ public final class SystemUiDeviceConfigFlags {
public static final String TASK_MANAGER_SHOW_FOOTER_DOT = "task_manager_show_footer_dot";
/**
- * (boolean) Whether to enable the adapter conversion in RemoteViews
- */
- public static final String REMOTEVIEWS_ADAPTER_CONVERSION =
- "CursorControlFeature__remoteviews_adapter_conversion";
-
- /**
- * The key name used in app core settings for {@link #REMOTEVIEWS_ADAPTER_CONVERSION}
- */
- public static final String KEY_REMOTEVIEWS_ADAPTER_CONVERSION =
- "systemui__remoteviews_adapter_conversion";
-
- /**
- * Default value for whether the adapter conversion is enabled or not. This is set for
- * RemoteViews and should not be a common practice.
- */
- public static final boolean REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT = false;
-
- /**
* (boolean) Whether the task manager should show a stop button if the app is allowlisted
* by the user.
*/
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index f460233f0edd..96740c59ec06 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -109,6 +109,7 @@ public class Cuj {
* eg: Exit the app using back gesture.
*/
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78;
+ // 79 is reserved.
public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80;
public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81;
@@ -119,10 +120,11 @@ public class Cuj {
public static final int CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY = 84;
public static final int CUJ_PREDICTIVE_BACK_CROSS_TASK = 85;
public static final int CUJ_PREDICTIVE_BACK_HOME = 86;
+ public static final int CUJ_LAUNCHER_SEARCH_QSB_OPEN = 87;
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
@VisibleForTesting
- static final int LAST_CUJ = CUJ_PREDICTIVE_BACK_HOME;
+ static final int LAST_CUJ = CUJ_LAUNCHER_SEARCH_QSB_OPEN;
/** @hide */
@IntDef({
@@ -204,6 +206,7 @@ public class Cuj {
CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY,
CUJ_PREDICTIVE_BACK_CROSS_TASK,
CUJ_PREDICTIVE_BACK_HOME,
+ CUJ_LAUNCHER_SEARCH_QSB_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -295,6 +298,8 @@ public class Cuj {
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_ACTIVITY;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_TASK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_TASK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_HOME] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_OPEN] =
+ FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_OPEN;
}
private Cuj() {
@@ -467,6 +472,8 @@ public class Cuj {
return "PREDICTIVE_BACK_CROSS_TASK";
case CUJ_PREDICTIVE_BACK_HOME:
return "PREDICTIVE_BACK_HOME";
+ case CUJ_LAUNCHER_SEARCH_QSB_OPEN:
+ return "LAUNCHER_SEARCH_QSB_OPEN";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/net/TEST_MAPPING b/core/java/com/android/internal/net/TEST_MAPPING
index 971ad36eecba..f935946c95c7 100644
--- a/core/java/com/android/internal/net/TEST_MAPPING
+++ b/core/java/com/android/internal/net/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "FrameworksNetTests",
"options": [
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 7d78f299c625..0be98040af73 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -72,6 +72,7 @@ import java.util.concurrent.locks.ReentrantLock;
* All interfaces in BatteryStatsHistory should only be called by BatteryStatsImpl and protected by
* locks on BatteryStatsImpl object.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BatteryStatsHistory {
private static final boolean DEBUG = false;
private static final String TAG = "BatteryStatsHistory";
@@ -259,6 +260,7 @@ public class BatteryStatsHistory {
* until the first change occurs.
*/
@VisibleForTesting
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static class TraceDelegate {
// Note: certain tests currently run as platform_app which is not allowed
// to set debug system properties. To ensure that system properties are set
@@ -391,10 +393,18 @@ public class BatteryStatsHistory {
public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
MonotonicClock monotonicClock) {
+ this(maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock,
+ new TraceDelegate());
+ }
+
+ @VisibleForTesting
+ public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
+ HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
+ MonotonicClock monotonicClock, TraceDelegate traceDelegate) {
mMaxHistoryFiles = maxHistoryFiles;
mMaxHistoryBufferSize = maxHistoryBufferSize;
mStepDetailsCalculator = stepDetailsCalculator;
- mTracer = new TraceDelegate();
+ mTracer = traceDelegate;
mClock = clock;
mMonotonicClock = monotonicClock;
@@ -2096,6 +2106,7 @@ public class BatteryStatsHistory {
* fewer bytes. It is a bit more expensive than just writing the long into the parcel,
* but at scale saves a lot of storage and allows recording of longer battery history.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static final class VarintParceler {
/**
* Writes an array of longs into Parcel using the varint format, see
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index 6bd5898b1637..2dffe15dc4be 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -28,6 +28,7 @@ import java.util.Iterator;
/**
* An iterator for {@link BatteryStats.HistoryItem}'s.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.HistoryItem>,
AutoCloseable {
private static final boolean DEBUG = false;
diff --git a/core/java/com/android/internal/os/BinderCallHeavyHitterWatcher.java b/core/java/com/android/internal/os/BinderCallHeavyHitterWatcher.java
index 7701761baac8..00043cfcd56b 100644
--- a/core/java/com/android/internal/os/BinderCallHeavyHitterWatcher.java
+++ b/core/java/com/android/internal/os/BinderCallHeavyHitterWatcher.java
@@ -33,6 +33,7 @@ import java.util.List;
* A watcher which makes stats on the incoming binder transaction, if the amount of some type of
* transactions exceeds the threshold, the listener will be notified.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class BinderCallHeavyHitterWatcher {
private static final String TAG = "BinderCallHeavyHitterWatcher";
diff --git a/core/java/com/android/internal/os/BinderDeathDispatcher.java b/core/java/com/android/internal/os/BinderDeathDispatcher.java
index 8ca6241e63c6..e7abe2a83ad8 100644
--- a/core/java/com/android/internal/os/BinderDeathDispatcher.java
+++ b/core/java/com/android/internal/os/BinderDeathDispatcher.java
@@ -36,6 +36,7 @@ import com.android.internal.annotations.VisibleForTesting;
*
* test with: atest FrameworksCoreTests:BinderDeathDispatcherTest
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BinderDeathDispatcher<T extends IInterface> {
private static final String TAG = "BinderDeathDispatcher";
diff --git a/core/java/com/android/internal/os/BinderLatencyBuckets.java b/core/java/com/android/internal/os/BinderLatencyBuckets.java
index d7d2d6a8f9dd..5679bc778eee 100644
--- a/core/java/com/android/internal/os/BinderLatencyBuckets.java
+++ b/core/java/com/android/internal/os/BinderLatencyBuckets.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
* Generates the bucket thresholds (with a custom logarithmic scale) for a histogram to store
* latency samples in.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BinderLatencyBuckets {
private static final String TAG = "BinderLatencyBuckets";
private final int[] mBuckets;
diff --git a/core/java/com/android/internal/os/BinderfsStatsReader.java b/core/java/com/android/internal/os/BinderfsStatsReader.java
index 9cc4a35b5c65..66f91e192a88 100644
--- a/core/java/com/android/internal/os/BinderfsStatsReader.java
+++ b/core/java/com/android/internal/os/BinderfsStatsReader.java
@@ -43,6 +43,7 @@ import java.util.function.Predicate;
* free async space 520192
* ...
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BinderfsStatsReader {
private final String mPath;
diff --git a/core/java/com/android/internal/os/CachedDeviceState.java b/core/java/com/android/internal/os/CachedDeviceState.java
index 334cca317c30..ac92f866eb7e 100644
--- a/core/java/com/android/internal/os/CachedDeviceState.java
+++ b/core/java/com/android/internal/os/CachedDeviceState.java
@@ -30,6 +30,7 @@ import java.util.ArrayList;
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class CachedDeviceState {
private volatile boolean mScreenInteractive;
private volatile boolean mCharging;
diff --git a/core/java/com/android/internal/os/Clock.java b/core/java/com/android/internal/os/Clock.java
index 45007c48777f..c2403d1e9f89 100644
--- a/core/java/com/android/internal/os/Clock.java
+++ b/core/java/com/android/internal/os/Clock.java
@@ -21,6 +21,7 @@ import android.os.SystemClock;
/**
* A wrapper for SystemClock, intended for mocking in unit tests.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public abstract class Clock {
/** Elapsed Realtime, see SystemClock.elapsedRealtime() */
public long elapsedRealtime() {
diff --git a/core/java/com/android/internal/os/CpuScalingPolicies.java b/core/java/com/android/internal/os/CpuScalingPolicies.java
index 6dbe8ab5f567..f61cf97c3277 100644
--- a/core/java/com/android/internal/os/CpuScalingPolicies.java
+++ b/core/java/com/android/internal/os/CpuScalingPolicies.java
@@ -27,6 +27,7 @@ import java.util.Arrays;
* CPU scaling policies: the policy IDs and corresponding supported scaling for those
* policies.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class CpuScalingPolicies {
private final SparseArray<int[]> mCpusByPolicy;
private final SparseArray<int[]> mFreqsByPolicy;
diff --git a/core/java/com/android/internal/os/CpuScalingPolicyReader.java b/core/java/com/android/internal/os/CpuScalingPolicyReader.java
index c96089a5c9c9..0d272fdd1578 100644
--- a/core/java/com/android/internal/os/CpuScalingPolicyReader.java
+++ b/core/java/com/android/internal/os/CpuScalingPolicyReader.java
@@ -40,6 +40,7 @@ import java.util.regex.Pattern;
* href="https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html
* #policy-interface-in-sysfs">Policy Interface in sysfs</a>
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class CpuScalingPolicyReader {
private static final String TAG = "CpuScalingPolicyReader";
private static final String CPUFREQ_DIR = "/sys/devices/system/cpu/cpufreq";
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 0843741d237c..5b6d1b63a42f 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -244,7 +244,8 @@ public class KernelCpuThreadReader {
}
/** Set the UID predicate for {@link #getProcessCpuUsage} */
- void setUidPredicate(Predicate<Integer> uidPredicate) {
+ @VisibleForTesting
+ public void setUidPredicate(Predicate<Integer> uidPredicate) {
mUidPredicate = uidPredicate;
}
diff --git a/core/java/com/android/internal/os/LoggingPrintStream.java b/core/java/com/android/internal/os/LoggingPrintStream.java
index d27874cd3be2..4bf92bb5e256 100644
--- a/core/java/com/android/internal/os/LoggingPrintStream.java
+++ b/core/java/com/android/internal/os/LoggingPrintStream.java
@@ -36,6 +36,7 @@ import com.android.internal.annotations.VisibleForTesting;
* {@hide}
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public abstract class LoggingPrintStream extends PrintStream {
private final StringBuilder builder = new StringBuilder();
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 0645eb7f0835..bbcea8af2b87 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -36,6 +36,7 @@ import java.util.concurrent.ThreadLocalRandom;
*
* @hide Only for use within the system server.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class LooperStats implements Looper.Observer {
public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
private static final int SESSION_POOL_SIZE = 50;
diff --git a/core/java/com/android/internal/os/MonotonicClock.java b/core/java/com/android/internal/os/MonotonicClock.java
index 661628a8c148..c3bcfa6b2cc2 100644
--- a/core/java/com/android/internal/os/MonotonicClock.java
+++ b/core/java/com/android/internal/os/MonotonicClock.java
@@ -40,6 +40,7 @@ import java.nio.charset.StandardCharsets;
* A clock that is similar to SystemClock#elapsedRealtime(), except that it is not reset
* on reboot, but keeps going.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class MonotonicClock {
private static final String TAG = "MonotonicClock";
diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java
index 1a7efac82278..56263fb924ea 100644
--- a/core/java/com/android/internal/os/PowerStats.java
+++ b/core/java/com/android/internal/os/PowerStats.java
@@ -41,6 +41,7 @@ import java.util.Objects;
* Container for power stats, acquired by various PowerStatsCollector classes. See subclasses for
* details.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class PowerStats {
private static final String TAG = "PowerStats";
@@ -67,6 +68,7 @@ public final class PowerStats {
* This descriptor is used for storing PowerStats and can also be used by power models
* to adjust the algorithm in accordance with the stats available on the device.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static class Descriptor {
public static final String XML_TAG_DESCRIPTOR = "descriptor";
private static final String XML_ATTR_ID = "id";
diff --git a/core/java/com/android/internal/os/ProcLocksReader.java b/core/java/com/android/internal/os/ProcLocksReader.java
index 9ddb8c75f5c8..6b85e08877ae 100644
--- a/core/java/com/android/internal/os/ProcLocksReader.java
+++ b/core/java/com/android/internal/os/ProcLocksReader.java
@@ -34,6 +34,7 @@ import java.io.IOException;
* 3: POSIX ADVISORY READ 3888 fd:09:13992 128 128
* 4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ProcLocksReader {
private final String mPath;
private ProcFileReader mReader = null;
diff --git a/core/java/com/android/internal/os/ProcStatsUtil.java b/core/java/com/android/internal/os/ProcStatsUtil.java
index 0002447fda2a..b67190bc7e88 100644
--- a/core/java/com/android/internal/os/ProcStatsUtil.java
+++ b/core/java/com/android/internal/os/ProcStatsUtil.java
@@ -30,6 +30,7 @@ import java.io.IOException;
* Utility functions for reading {@code proc} files
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class ProcStatsUtil {
private static final boolean DEBUG = false;
@@ -92,10 +93,24 @@ public final class ProcStatsUtil {
* seen, or at the end of the file
*/
@Nullable
+ @android.ravenwood.annotation.RavenwoodReplace
public static String readTerminatedProcFile(String path, byte terminator) {
// Permit disk reads here, as /proc isn't really "on disk" and should be fast.
// TODO: make BlockGuard ignore /proc/ and /sys/ files perhaps?
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ return readTerminatedProcFileInternal(path, terminator);
+ } finally {
+ StrictMode.setThreadPolicy(savedPolicy);
+ }
+ }
+
+ public static String readTerminatedProcFile$ravenwood(String path, byte terminator) {
+ // No StrictMode under Ravenwood
+ return readTerminatedProcFileInternal(path, terminator);
+ }
+
+ private static String readTerminatedProcFileInternal(String path, byte terminator) {
try (FileInputStream is = new FileInputStream(path)) {
ByteArrayOutputStream byteStream = null;
final byte[] buffer = new byte[READ_SIZE];
@@ -147,8 +162,6 @@ public final class ProcStatsUtil {
Slog.d(TAG, "Failed to open proc file", e);
}
return null;
- } finally {
- StrictMode.setThreadPolicy(savedPolicy);
}
}
}
diff --git a/core/java/com/android/internal/os/StoragedUidIoStatsReader.java b/core/java/com/android/internal/os/StoragedUidIoStatsReader.java
index 9b0346923cd3..2d485dac4859 100644
--- a/core/java/com/android/internal/os/StoragedUidIoStatsReader.java
+++ b/core/java/com/android/internal/os/StoragedUidIoStatsReader.java
@@ -38,6 +38,7 @@ import java.nio.file.Files;
* This provides the number of bytes/chars read/written in foreground/background for each uid.
* The file contains a monotonically increasing count of bytes/chars for a single boot.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class StoragedUidIoStatsReader {
private static final String TAG = StoragedUidIoStatsReader.class.getSimpleName();
@@ -73,8 +74,21 @@ public class StoragedUidIoStatsReader {
*
* @param callback The callback to invoke for each line of the proc file.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public void readAbsolute(Callback callback) {
final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try {
+ readAbsoluteInternal(callback);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ }
+
+ public void readAbsolute$ravenwood(Callback callback) {
+ readAbsoluteInternal(callback);
+ }
+
+ private void readAbsoluteInternal(Callback callback) {
File file = new File(sUidIoFile);
try (BufferedReader reader = Files.newBufferedReader(file.toPath())) {
String line;
@@ -106,8 +120,6 @@ public class StoragedUidIoStatsReader {
}
} catch (IOException e) {
Slog.e(TAG, "Failed to read " + sUidIoFile + ": " + e.getMessage());
- } finally {
- StrictMode.setThreadPolicyMask(oldMask);
}
}
}
diff --git a/core/java/com/android/internal/pm/parsing/AppInfoUtils.java b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java
new file mode 100644
index 000000000000..38a2fe2a77a1
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java
@@ -0,0 +1,124 @@
+/*
+ * 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.internal.pm.parsing;
+
+import android.annotation.CheckResult;
+import android.content.pm.ApplicationInfo;
+
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
+
+public class AppInfoUtils {
+
+ /**
+ * @see ApplicationInfo#flags
+ */
+ public static int appInfoFlags(AndroidPackage pkg) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
+ | flag(pkg.isHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
+ | flag(pkg.isBackupAllowed(), ApplicationInfo.FLAG_ALLOW_BACKUP)
+ | flag(pkg.isKillAfterRestoreAllowed(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
+ | flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
+ | flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
+ | flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
+ | flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
+ | flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
+ | flag(pkg.isDeclaredHavingCode(), ApplicationInfo.FLAG_HAS_CODE)
+ | flag(pkg.isTaskReparentingAllowed(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+ | flag(pkg.isClearUserDataAllowed(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
+ | flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
+ | flag(pkg.isCleartextTrafficAllowed(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+ | flag(pkg.isRtlSupported(), ApplicationInfo.FLAG_SUPPORTS_RTL)
+ | flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
+ | flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
+ | flag(pkg.isExtractNativeLibrariesRequested(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
+ | flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
+ | flag(pkg.isSmallScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
+ | flag(pkg.isNormalScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
+ | flag(pkg.isLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
+ | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
+ | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
+ | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
+ | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
+ | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
+
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+ /** @see ApplicationInfo#privateFlags */
+ public static int appInfoPrivateFlags(AndroidPackage pkg) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY)
+ | flag(pkg.isResourceOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY)
+ | flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING)
+ | flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS)
+ | flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL)
+ | flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND)
+ | flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX)
+ | flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
+ | flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
+ | flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
+ | flag(pkg.isClearUserDataOnFailedRestoreAllowed(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
+ | flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
+ | flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
+ | flag(pkg.isNonSdkApiRequested(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
+ | flag(pkg.isUserDataFragile(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
+ | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
+ | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
+ | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+ | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
+ | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+ | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
+ | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
+
+ Boolean resizeableActivity = pkg.getResizeableActivity();
+ if (resizeableActivity != null) {
+ if (resizeableActivity) {
+ pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+ } else {
+ pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
+ }
+ }
+
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+
+ /** @see ApplicationInfo#privateFlagsExt */
+ public static int appInfoPrivateFlagsExt(AndroidPackage pkg,
+ boolean isAllowlistedForHiddenApis) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE)
+ | flag(pkg.hasRequestForegroundServiceExemption(), ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
+ | flag(pkg.isAttributionsUserVisible(), ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
+ | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)
+ | flag(isAllowlistedForHiddenApis, ApplicationInfo.PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS);
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+ @CheckResult
+ private static int flag(boolean hasFlag, int flag) {
+ return hasFlag ? flag : 0;
+ }
+}
diff --git a/core/java/com/android/internal/pm/parsing/PackageParserException.java b/core/java/com/android/internal/pm/parsing/PackageParserException.java
new file mode 100644
index 000000000000..4250bbd9baf6
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/PackageParserException.java
@@ -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.internal.pm.parsing;
+
+public class PackageParserException extends Exception {
+ public final int error;
+
+ public PackageParserException(int error, String detailMessage) {
+ super(detailMessage);
+ this.error = error;
+ }
+
+ public PackageParserException(int error, String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ this.error = error;
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java
new file mode 100644
index 000000000000..e65f1c960b6a
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java
@@ -0,0 +1,128 @@
+/*
+ * 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.internal.pm.parsing.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+
+import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.server.pm.pkg.AndroidPackage;
+
+/** @hide */
+public class AndroidPackageLegacyUtils {
+
+ private AndroidPackageLegacyUtils() {
+ }
+
+ /**
+ * Returns the primary ABI as parsed from the package. Used only during parsing and derivation.
+ * Otherwise prefer {@link PackageState#getPrimaryCpuAbi()}.
+ */
+ public static String getRawPrimaryCpuAbi(AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).getPrimaryCpuAbi();
+ }
+
+ /**
+ * Returns the secondary ABI as parsed from the package. Used only during parsing and
+ * derivation. Otherwise prefer {@link PackageState#getSecondaryCpuAbi()}.
+ */
+ public static String getRawSecondaryCpuAbi(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi();
+ }
+
+ @Deprecated
+ @NonNull
+ public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).toAppInfoWithoutState();
+ }
+
+ /**
+ * Replacement of unnecessary legacy getRealPackage. Only returns a value if the package was
+ * actually renamed.
+ */
+ @Nullable
+ public static String getRealPackageOrNull(@NonNull AndroidPackage pkg, boolean isSystem) {
+ if (pkg.getOriginalPackages().isEmpty() || !isSystem) {
+ return null;
+ }
+
+ return pkg.getManifestPackageName();
+ }
+
+ public static void fillVersionCodes(@NonNull AndroidPackage pkg, @NonNull PackageInfo info) {
+ info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
+ info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isSystem}
+ */
+ @Deprecated
+ public static boolean isSystem(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isSystem();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isSystemExt}
+ */
+ @Deprecated
+ public static boolean isSystemExt(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isSystemExt();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isPrivileged}
+ */
+ @Deprecated
+ public static boolean isPrivileged(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isPrivileged();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isOem}
+ */
+ @Deprecated
+ public static boolean isOem(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isOem();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isVendor}
+ */
+ @Deprecated
+ public static boolean isVendor(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isVendor();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isProduct}
+ */
+ @Deprecated
+ public static boolean isProduct(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isProduct();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isOdm}
+ */
+ @Deprecated
+ public static boolean isOdm(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isOdm();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index da58d47edbfe..83acc47d637f 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.parsing.pkg;
+package com.android.internal.pm.parsing.pkg;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
@@ -50,47 +50,44 @@ import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
-import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
-import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.AppInfoUtils;
import com.android.internal.pm.pkg.AndroidPackageSplitImpl;
+import com.android.internal.pm.pkg.SEInfoUtil;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl;
import com.android.internal.pm.pkg.component.ParsedAttribution;
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessImpl;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceImpl;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackageSplit;
-import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl;
-import com.android.server.pm.pkg.component.ParsedAttributionImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedProcessImpl;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedServiceImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import libcore.util.EmptyArray;
@@ -422,8 +419,10 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
@NonNull
public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
- @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) {
- return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp);
+ @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp,
+ @Nullable ParsingPackageUtils.Callback callback) {
+ return new PackageImpl(
+ packageName, baseCodePath, codePath, manifestArray, isCoreApp, callback);
}
/**
@@ -453,7 +452,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
@NonNull
@VisibleForTesting
public static ParsingPackage forTesting(String packageName, String baseCodePath) {
- return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false);
+ return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false, null);
}
@NonNull
@@ -727,26 +726,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
this.usesSdkLibrariesVersionsMajor, versionMajor, true);
this.usesSdkLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
this.usesSdkLibrariesCertDigests, certSha256Digests, true);
- this.usesSdkLibrariesOptional = appendBoolean(this.usesSdkLibrariesOptional,
+ this.usesSdkLibrariesOptional = ArrayUtils.appendBoolean(this.usesSdkLibrariesOptional,
usesSdkLibrariesOptional);
return this;
}
- /**
- * Adds value to given array if not already present, providing set-like
- * behavior.
- */
- public static boolean[] appendBoolean(@Nullable boolean[] cur, boolean val) {
- if (cur == null) {
- return new boolean[] { val };
- }
- final int N = cur.length;
- boolean[] ret = new boolean[N + 1];
- System.arraycopy(cur, 0, ret, 0, N);
- ret[N] = val;
- return ret;
- }
-
@Override
public PackageImpl addUsesStaticLibrary(String libraryName, long version,
String[] certSha256Digests) {
@@ -2694,12 +2678,16 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
private String mBaseAppDataCredentialProtectedDirForSystemUser;
private String mBaseAppDataDeviceProtectedDirForSystemUser;
+ ParsingPackageUtils.Callback mCallback;
+
@VisibleForTesting
public PackageImpl(@NonNull String packageName, @NonNull String baseApkPath,
- @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp) {
+ @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp,
+ @Nullable ParsingPackageUtils.Callback callback) {
this.packageName = TextUtils.safeIntern(packageName);
this.mBaseApkPath = baseApkPath;
this.mPath = path;
+ this.mCallback = callback;
if (manifestArray != null) {
versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
@@ -2750,9 +2738,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
private void assignDerivedFields2() {
- mBaseAppInfoFlags = PackageInfoUtils.appInfoFlags(this, null);
- mBaseAppInfoPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null);
- mBaseAppInfoPrivateFlagsExt = PackageInfoUtils.appInfoPrivateFlagsExt(this, null);
+ mBaseAppInfoFlags = AppInfoUtils.appInfoFlags(this);
+ mBaseAppInfoPrivateFlags = AppInfoUtils.appInfoPrivateFlags(this);
+ mBaseAppInfoPrivateFlagsExt = AppInfoUtils.appInfoPrivateFlagsExt(this,
+ mCallback == null ? false :
+ mCallback.getHiddenApiWhitelistedApps().contains(this.packageName));
String baseAppDataDir = Environment.getDataDirectoryPath(getVolumeUuid()) + File.separator;
String systemUserSuffix = File.separator + UserHandle.USER_SYSTEM + File.separator;
mBaseAppDataCredentialProtectedDirForSystemUser = TextUtils.safeIntern(
@@ -3087,7 +3077,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
appInfo.primaryCpuAbi = primaryCpuAbi;
appInfo.secondaryCpuAbi = secondaryCpuAbi;
appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
- appInfo.seInfoUser = SELinuxUtil.COMPLETE_STR;
+ appInfo.seInfoUser = SEInfoUtil.COMPLETE_STR;
appInfo.uid = uid;
return appInfo;
}
diff --git a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
index d9625050d28c..a670c6d5aff4 100644
--- a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java
+++ b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.permission;
+package com.android.internal.pm.permission;
import android.Manifest;
import android.annotation.NonNull;
@@ -67,7 +67,7 @@ public class CompatibilityPermissionInfo {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -97,10 +97,10 @@ public class CompatibilityPermissionInfo {
}
@DataClass.Generated(
- time = 1627674427184L,
+ time = 1701338392152L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final android.content.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java",
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final com.android.internal.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/com/android/internal/pm/pkg/SEInfoUtil.java b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java
new file mode 100644
index 000000000000..a6988829ca92
--- /dev/null
+++ b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java
@@ -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.internal.pm.pkg;
+
+/**
+ * Utility methods that need to be used in application space.
+ * @hide
+ */
+public final class SEInfoUtil {
+
+ /** Append to existing seinfo label for instant apps @hide */
+ public static final String INSTANT_APP_STR = ":ephemeralapp";
+
+ /** Append to existing seinfo when modifications are complete @hide */
+ public static final String COMPLETE_STR = ":complete";
+}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java
index 1964df0853fd..fd5f0f079da9 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java
@@ -14,19 +14,11 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.internal.pm.pkg.component.ParsedActivity;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
-import com.android.internal.pm.pkg.component.ParsedProcess;
-import com.android.internal.pm.pkg.component.ParsedProvider;
-
/**
* Contains mutation methods so that code doesn't have to cast to the Impl. Meant to eventually
* be removed once all post-parsing mutation is moved to parsing.
diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
index 019ca1315af8..db08005c833e 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.AttrRes;
import android.annotation.NonNull;
@@ -29,14 +29,9 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.PackageUserState;
-import com.android.server.pm.pkg.PackageUserStateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -173,16 +168,4 @@ public class ComponentParseUtils {
public static int getIcon(ParsedComponent component) {
return component.getIcon();
}
-
- public static boolean isMatch(PackageUserState state, boolean isSystem,
- boolean isPackageEnabled, ParsedMainComponent component, long flags) {
- return PackageUserStateUtils.isMatch(state, isSystem, isPackageEnabled,
- component.isEnabled(), component.isDirectBootAware(), component.getName(), flags);
- }
-
- public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled,
- ParsedMainComponent parsedComponent, long flags) {
- return PackageUserStateUtils.isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
- parsedComponent.getName(), flags);
- }
}
diff --git a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
index dd54cfca6518..0b045919fb13 100644
--- a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java
+++ b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.content.pm.parsing.result.ParseInput;
@@ -27,7 +27,6 @@ import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.SystemConfig;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -48,9 +47,8 @@ public class InstallConstraintsTagParser {
* @hide
*/
public static ParseResult<ParsingPackage> parseInstallConstraints(
- ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)
- throws XmlPullParserException, IOException {
- Set<String> allowlist = SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser,
+ Set<String> allowlist) throws XmlPullParserException, IOException {
if (!allowlist.contains(pkg.getPackageName())) {
return input.skip("install-constraints cannot be used by this package");
}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
index f02790189cc0..2f977eea127d 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -22,8 +22,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForStringSet;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForStringSet;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,10 +36,9 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArraySet;
-import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import java.util.Collections;
import java.util.Locale;
@@ -380,7 +379,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -696,10 +695,10 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
}
@DataClass.Generated(
- time = 1669437519576L,
+ time = 1701338377709L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java",
- inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java",
+ inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedActivityImpl> CREATOR\npublic static @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
index 64985bdfd54f..c3f7dab3c46a 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,11 +48,10 @@ import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
index cfed19aa0934..27f7eee1a308 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -60,7 +59,7 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService, Par
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -248,9 +247,9 @@ public class ParsedApexSystemServiceImpl implements ParsedApexSystemService, Par
};
@DataClass.Generated(
- time = 1643723578605L,
+ time = 1701710844088L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java",
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java",
inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedApexSystemService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java
index d3fb29b8aa66..c69213f11f85 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.R;
import android.annotation.NonNull;
@@ -25,8 +25,6 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
-import com.android.internal.pm.pkg.component.ParsedApexSystemService;
-
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
index 62b994724346..e3bfb38802db 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.StringRes;
@@ -22,7 +22,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedAttribution;
import com.android.internal.util.DataClass;
import java.util.ArrayList;
@@ -60,7 +59,7 @@ public class ParsedAttributionImpl implements ParsedAttribution, Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -207,10 +206,10 @@ public class ParsedAttributionImpl implements ParsedAttribution, Parcelable {
};
@DataClass.Generated(
- time = 1641431950829L,
+ time = 1701338881658L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java",
- inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java",
+ inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java
index 411220ae42e8..ee5c3204ccd1 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +26,6 @@ import android.content.res.XmlResourceParser;
import android.util.ArraySet;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedAttribution;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
index 512e5c7023c7..7ee22f30ace0 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import static java.util.Collections.emptyMap;
@@ -32,12 +32,10 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -200,7 +198,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -306,10 +304,10 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
}
@DataClass.Generated(
- time = 1641414207885L,
+ time = 1701445673589L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java",
- inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List<android.content.pm.parsing.component.ParsedIntentInfoImpl> intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.PackageManager.Property> mProperties\n void addIntent(android.content.pm.parsing.component.ParsedIntentInfoImpl)\n void addProperty(android.content.pm.PackageManager.Property)\npublic android.content.pm.parsing.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.parsing.component.ParsedIntentInfo> getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java",
+ inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List<com.android.internal.pm.pkg.component.ParsedIntentInfoImpl> intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.PackageManager.Property> mProperties\npublic void addIntent(com.android.internal.pm.pkg.component.ParsedIntentInfoImpl)\npublic void addProperty(android.content.pm.PackageManager.Property)\npublic com.android.internal.pm.pkg.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.internal.pm.pkg.component.ParsedIntentInfo> getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java
index 9322cf0e90f6..9e2548b3bce3 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PackageManager;
@@ -32,8 +32,8 @@ import android.util.TypedValue;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
/** @hide */
class ParsedComponentUtils {
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
index 7bfad14d669a..07322e9dd912 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +26,6 @@ import android.os.Parcelable;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -112,7 +111,7 @@ public class ParsedInstrumentationImpl extends ParsedComponentImpl implements
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -166,10 +165,10 @@ public class ParsedInstrumentationImpl extends ParsedComponentImpl implements
}
@DataClass.Generated(
- time = 1641431951575L,
+ time = 1701445763455L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedInstrumentationImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java",
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedInstrumentationImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java
index a7116949b911..661c8b421fb4 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.parsing.result.ParseInput;
@@ -26,7 +26,6 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
index ab9404310078..adb49e9fde6d 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -23,7 +23,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.util.DataClass;
/**
@@ -54,7 +53,7 @@ public class ParsedIntentInfoImpl implements ParsedIntentInfo, Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -170,10 +169,10 @@ public class ParsedIntentInfoImpl implements ParsedIntentInfo, Parcelable {
};
@DataClass.Generated(
- time = 1641431952314L,
+ time = 1701445800363L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java",
- inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java",
+ inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
index e5e214d2292b..c6683cfc8331 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
import android.annotation.NonNull;
import android.content.Intent;
@@ -31,10 +31,9 @@ import android.util.Slog;
import android.util.TypedValue;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
index f322eef8c3a3..bb8f565d2032 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -25,7 +25,6 @@ import android.os.Parcelable;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -133,7 +132,7 @@ public class ParsedMainComponentImpl extends ParsedComponentImpl implements Pars
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -227,10 +226,10 @@ public class ParsedMainComponentImpl extends ParsedComponentImpl implements Pars
}
@DataClass.Generated(
- time = 1641414540422L,
+ time = 1701447884766L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedMainComponentImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java",
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedMainComponentImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java
index 8268f0fdfa3e..7e56180f72ce 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,10 +31,8 @@ import android.os.Build;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
index afe37bc3274c..3622019f36b9 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.util.DataClass;
/**
@@ -75,7 +74,7 @@ public class ParsedPermissionGroupImpl extends ParsedComponentImpl implements
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -172,10 +171,10 @@ public class ParsedPermissionGroupImpl extends ParsedComponentImpl implements
};
@DataClass.Generated(
- time = 1642132854167L,
+ time = 1701445837884L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java",
- inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override @com.android.internal.util.DataClass.Generated.Member void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.server.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java",
+ inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
index 69e33c8f281e..4dcce131168b 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,8 +24,6 @@ import android.text.TextUtils;
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -148,7 +146,7 @@ public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedP
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -162,7 +160,7 @@ public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedP
int requestRes,
int protectionLevel,
boolean tree,
- @Nullable ParsedPermissionGroupImpl parsedPermissionGroup,
+ @Nullable ParsedPermissionGroup parsedPermissionGroup,
@Nullable Set<String> knownCerts) {
this.backgroundPermission = backgroundPermission;
this.group = group;
@@ -237,10 +235,10 @@ public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedP
}
@DataClass.Generated(
- time = 1641414649731L,
+ time = 1701445829812L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java",
- inputSignatures = "private static com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable android.content.pm.parsing.component.ParsedPermissionGroupImpl parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedPermissionImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic android.content.pm.parsing.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java",
+ inputSignatures = "private static final com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable com.android.internal.pm.pkg.component.ParsedPermissionGroup parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedPermissionImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic com.android.internal.pm.pkg.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java
index 4b45d3742a2a..5651c1ca247f 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PermissionInfo;
@@ -31,10 +31,8 @@ import android.util.EventLog;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
index 40e3670b9261..212fb867e7df 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static java.util.Collections.emptySet;
@@ -25,7 +25,6 @@ import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -98,7 +97,7 @@ public class ParsedProcessImpl implements ParsedProcess, Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -304,10 +303,10 @@ public class ParsedProcessImpl implements ParsedProcess, Parcelable {
};
@DataClass.Generated(
- time = 1641431953775L,
+ time = 1701445656489L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.String> appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java",
+ inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.String> appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(com.android.internal.pm.pkg.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java
index a84954950f44..3b2056e7892e 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
@@ -27,11 +27,10 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java
index 81a3c17e2bb4..987fd4158418 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,7 +28,6 @@ import android.os.PatternMatcher;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -302,7 +301,7 @@ public class ParsedProviderImpl extends ParsedMainComponentImpl implements Parse
time = 1642560323360L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List<android.os.PatternMatcher> uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List<android.content.pm.PathPermission> pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedProviderImpl> CREATOR\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List<android.os.PatternMatcher> uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List<android.content.pm.PathPermission> pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedProviderImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
index 0b28a1214072..5d82d0469d56 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,9 +34,8 @@ import android.os.PatternMatcher;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
index ca8c45d1383c..f4662d803296 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,8 +26,6 @@ import android.os.Parcelable;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
-import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -107,7 +105,7 @@ public class ParsedServiceImpl extends ParsedMainComponentImpl implements Parsed
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -141,10 +139,10 @@ public class ParsedServiceImpl extends ParsedMainComponentImpl implements Parsed
}
@DataClass.Generated(
- time = 1641431954479L,
+ time = 1701445638370L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java",
- inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedServiceImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends android.content.pm.parsing.component.ParsedMainComponentImpl implements [android.content.pm.parsing.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java",
+ inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedServiceImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
index 171ef594f6fd..a1dd19a3bc90 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,9 +32,8 @@ import android.content.res.XmlResourceParser;
import android.os.Build;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
index 78377a836651..fd131dfd00c7 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedUsesPermission;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -51,7 +50,7 @@ public class ParsedUsesPermissionImpl implements ParsedUsesPermission, Parcelabl
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -158,10 +157,10 @@ public class ParsedUsesPermissionImpl implements ParsedUsesPermission, Parcelabl
};
@DataClass.Generated(
- time = 1641431955242L,
+ time = 1701445626268L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java",
- inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @android.content.pm.parsing.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java",
+ inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.pm.pkg.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index aa0fb2734382..dbe4fba5dfdb 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -30,7 +30,7 @@ import static android.os.Build.VERSION_CODES.DONUT;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.AnyRes;
import android.annotation.CheckResult;
@@ -57,7 +57,6 @@ import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
-import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -90,43 +89,40 @@ import android.util.apk.ApkSignatureVerifier;
import com.android.internal.R;
import com.android.internal.os.ClassLoaderFactory;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
+import com.android.internal.pm.pkg.component.ComponentParseUtils;
+import com.android.internal.pm.pkg.component.InstallConstraintsTagParser;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
+import com.android.internal.pm.pkg.component.ParsedActivityUtils;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceUtils;
import com.android.internal.pm.pkg.component.ParsedAttribution;
+import com.android.internal.pm.pkg.component.ParsedAttributionUtils;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationUtils;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoUtils;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessUtils;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderUtils;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceUtils;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
-import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.internal.pm.split.DefaultSplitAssetLoader;
+import com.android.internal.pm.split.SplitAssetDependencyLoader;
+import com.android.internal.pm.split.SplitAssetLoader;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.SharedUidMigration;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.permission.CompatibilityPermissionInfo;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ComponentParseUtils;
-import com.android.server.pm.pkg.component.InstallConstraintsTagParser;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedActivityUtils;
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceUtils;
-import com.android.server.pm.pkg.component.ParsedAttributionUtils;
-import com.android.server.pm.pkg.component.ParsedInstrumentationUtils;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.component.ParsedProcessUtils;
-import com.android.server.pm.pkg.component.ParsedProviderUtils;
-import com.android.server.pm.pkg.component.ParsedServiceUtils;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
-import com.android.server.pm.split.DefaultSplitAssetLoader;
-import com.android.server.pm.split.SplitAssetDependencyLoader;
-import com.android.server.pm.split.SplitAssetLoader;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -267,18 +263,6 @@ public class ParsingPackageUtils {
public @interface ParseFlags {}
/**
- * @see #parseDefault(ParseInput, File, int, List, boolean)
- */
- @NonNull
- public static ParseResult<ParsedPackage> parseDefaultOneTime(File file,
- @ParseFlags int parseFlags,
- @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
- boolean collectCertificates) {
- ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
- return parseDefault(input, file, parseFlags, splitPermissions, collectCertificates);
- }
-
- /**
* For cases outside of PackageManagerService when an APK needs to be parsed as a one-off
* request, without caching the input object and without querying the internal system state for
* feature support.
@@ -287,30 +271,10 @@ public class ParsingPackageUtils {
public static ParseResult<ParsedPackage> parseDefault(ParseInput input, File file,
@ParseFlags int parseFlags,
@NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
- boolean collectCertificates) {
- ParseResult<ParsedPackage> result;
+ boolean collectCertificates, Callback callback) {
ParsingPackageUtils parser = new ParsingPackageUtils(null /*separateProcesses*/,
- null /*displayMetrics*/, splitPermissions, new Callback() {
- @Override
- public boolean hasFeature(String feature) {
- // Assume the device doesn't support anything. This will affect permission
- // parsing and will force <uses-permission/> declarations to include all
- // requiredNotFeature permissions and exclude all requiredFeature
- // permissions. This mirrors the old behavior.
- return false;
- }
-
- @Override
- public ParsingPackage startParsingPackage(
- @NonNull String packageName,
- @NonNull String baseApkPath,
- @NonNull String path,
- @NonNull TypedArray manifestArray, boolean isCoreApp) {
- return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray,
- isCoreApp);
- }
- });
+ null /*displayMetrics*/, splitPermissions, callback);
var parseResult = parser.parsePackage(input, file, parseFlags);
if (parseResult.isError()) {
return input.error(parseResult);
@@ -1146,7 +1110,8 @@ public class ParsingPackageUtils {
case TAG_RESTRICT_UPDATE:
return parseRestrictUpdateHash(flags, input, pkg, res, parser);
case TAG_INSTALL_CONSTRAINTS:
- return parseInstallConstraints(input, pkg, res, parser);
+ return parseInstallConstraints(input, pkg, res, parser,
+ mCallback.getInstallConstraintsAllowlist());
case TAG_QUERIES:
return parseQueries(input, pkg, res, parser);
default:
@@ -1172,7 +1137,7 @@ public class ParsingPackageUtils {
}
boolean leaving = false;
- if (!SharedUidMigration.isDisabled()) {
+ if (PackageManager.ENABLE_SHARED_UID_MIGRATION) {
int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT);
}
@@ -1858,10 +1823,11 @@ public class ParsingPackageUtils {
return input.success(pkg);
}
- private static ParseResult<ParsingPackage> parseInstallConstraints(
- ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)
+ private static ParseResult<ParsingPackage> parseInstallConstraints(ParseInput input,
+ ParsingPackage pkg, Resources res, XmlResourceParser parser, Set<String> allowlist)
throws IOException, XmlPullParserException {
- return InstallConstraintsTagParser.parseInstallConstraints(input, pkg, res, parser);
+ return InstallConstraintsTagParser.parseInstallConstraints(
+ input, pkg, res, parser, allowlist);
}
private static ParseResult<ParsingPackage> parseQueries(ParseInput input, ParsingPackage pkg,
@@ -3485,5 +3451,9 @@ public class ParsingPackageUtils {
ParsingPackage startParsingPackage(@NonNull String packageName,
@NonNull String baseApkPath, @NonNull String path,
@NonNull TypedArray manifestArray, boolean isCoreApp);
+
+ @NonNull Set<String> getHiddenApiWhitelistedApps();
+
+ @NonNull Set<String> getInstallConstraintsAllowlist();
}
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java
index 1d159554e8a7..26822c649db7 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,10 +31,9 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.util.Parcelling;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java
index 0bb969f488fe..50c62437b192 100644
--- a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
@@ -21,9 +21,9 @@ import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java
index 56d92fbc95a2..c166cdcf9451 100644
--- a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.annotation.NonNull;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -24,8 +24,8 @@ import android.content.res.AssetManager;
import android.os.Build;
import android.util.SparseArray;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java b/core/java/com/android/internal/pm/split/SplitAssetLoader.java
index 845015916e60..c7c409d826ba 100644
--- a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java
+++ b/core/java/com/android/internal/pm/split/SplitAssetLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 9d0be4bf8ee6..8f00f79e7179 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -623,6 +623,21 @@ public class ArrayUtils {
* Adds value to given array if not already present, providing set-like
* behavior.
*/
+ public static boolean[] appendBoolean(@Nullable boolean[] cur, boolean val) {
+ if (cur == null) {
+ return new boolean[] { val };
+ }
+ final int N = cur.length;
+ boolean[] ret = new boolean[N + 1];
+ System.arraycopy(cur, 0, ret, 0, N);
+ ret[N] = val;
+ return ret;
+ }
+
+ /**
+ * Adds value to given array if not already present, providing set-like
+ * behavior.
+ */
public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
return appendLong(cur, val, false);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 28fd2b488426..bf8e6135fd01 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -897,13 +897,26 @@ public class LockPatternUtils {
}
/**
- * Returns true if {@code userHandle} is a managed profile with separate challenge.
+ * Returns true if {@code userHandle} is a profile with separate challenge.
+ * <p>
+ * Returns false if {@code userHandle} is a profile with unified challenge, a profile whose
+ * credential is not shareable with its parent, or a non-profile user.
*/
public boolean isSeparateProfileChallengeEnabled(int userHandle) {
return isCredentialSharableWithParent(userHandle) && hasSeparateChallenge(userHandle);
}
/**
+ * Returns true if {@code userHandle} is a profile with unified challenge.
+ * <p>
+ * Returns false if {@code userHandle} is a profile with separate challenge, a profile whose
+ * credential is not shareable with its parent, or a non-profile user.
+ */
+ public boolean isProfileWithUnifiedChallenge(int userHandle) {
+ return isCredentialSharableWithParent(userHandle) && !hasSeparateChallenge(userHandle);
+ }
+
+ /**
* Returns true if {@code userHandle} is a managed profile with unified challenge.
*/
public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index c88763ce6c97..18d5f6db6ac9 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -134,12 +134,12 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
}
/**
- * Creates a LockscreenCredential object representing a managed password for profile with
- * unified challenge. This credentiall will have type {@code CREDENTIAL_TYPE_PASSWORD} for now.
- * TODO: consider add a new credential type for this. This can then supersede the
- * isLockTiedToParent argument in various places in LSS.
+ * Creates a LockscreenCredential object representing the system-generated, system-managed
+ * password for a profile with unified challenge. This credential has type {@code
+ * CREDENTIAL_TYPE_PASSWORD} for now. TODO: consider add a new credential type for this. This
+ * can then supersede the isLockTiedToParent argument in various places in LSS.
*/
- public static LockscreenCredential createManagedPassword(@NonNull byte[] password) {
+ public static LockscreenCredential createUnifiedProfilePassword(@NonNull byte[] password) {
return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
Arrays.copyOf(password, password.length), /* hasInvalidChars= */ false);
}
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index f86595f1ea7b..adb0c6959f12 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -58,6 +58,7 @@ import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import java.security.PublicKey;
import java.util.List;
@@ -690,7 +691,7 @@ public interface AndroidPackage {
/**
* The names of packages to adopt ownership of permissions from, parsed under {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
+ * ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
*
* @see R.styleable#AndroidManifestOriginalPackage_name
* @hide
@@ -795,7 +796,7 @@ public interface AndroidPackage {
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestKeySet
* @see R.styleable#AndroidManifestPublicKey
@@ -1266,7 +1267,7 @@ public interface AndroidPackage {
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestUpgradeKeySet
* @hide
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 91dfc6023e42..55100a5347fd 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -282,6 +282,11 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
void android_os_Process_setProcessFrozen(
JNIEnv *env, jobject clazz, jint pid, jint uid, jboolean freeze)
{
+ if (uid < 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "uid is negative: %d", uid);
+ return;
+ }
+
bool success = true;
if (freeze) {
@@ -305,6 +310,11 @@ jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
}
jint android_os_Process_createProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid) {
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return createProcessGroup(uid, pid);
}
@@ -590,12 +600,21 @@ void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
{
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return setuid(uid) == 0 ? 0 : errno;
}
-jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
-{
- return setgid(uid) == 0 ? 0 : errno;
+jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint gid) {
+ if (gid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "gid is negative: %d", gid);
+ }
+
+ return setgid(gid) == 0 ? 0 : errno;
}
static int pid_compare(const void* v1, const void* v2)
@@ -1235,11 +1254,21 @@ jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz,
jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid)
{
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return killProcessGroup(uid, pid, SIGKILL);
}
jint android_os_Process_sendSignalToProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid,
jint signal) {
+ if (uid < 0) {
+ return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "uid is negative: %d", uid);
+ }
+
return sendSignalToProcessGroup(uid, pid, signal);
}
@@ -1258,6 +1287,11 @@ static jint android_os_Process_nativePidFdOpen(JNIEnv* env, jobject, jint pid, j
}
void android_os_Process_freezeCgroupUID(JNIEnv* env, jobject clazz, jint uid, jboolean freeze) {
+ if (uid < 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "uid is negative: %d", uid);
+ return;
+ }
+
bool success = true;
if (freeze) {
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 87ab4969040e..54c4cd50a902 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -63,6 +63,7 @@ class NativeCommandBuffer {
std::optional<std::pair<char*, char*>> readLine(FailFn fail_fn) {
char* result = mBuffer + mNext;
while (true) {
+ // We have scanned up to, but not including mNext for this line's newline.
if (mNext == mEnd) {
if (mEnd == MAX_COMMAND_BYTES) {
return {};
@@ -89,7 +90,7 @@ class NativeCommandBuffer {
} else {
mNext = nl - mBuffer + 1;
if (--mLinesLeft < 0) {
- fail_fn("ZygoteCommandBuffer.readLine attempted to read past mEnd of command");
+ fail_fn("ZygoteCommandBuffer.readLine attempted to read past end of command");
}
return std::make_pair(result, nl);
}
@@ -125,8 +126,8 @@ class NativeCommandBuffer {
mEnd += lineLen + 1;
}
- // Clear mBuffer, start reading new command, return the number of arguments, leaving mBuffer
- // positioned at the beginning of first argument. Return 0 on EOF.
+ // Start reading new command, return the number of arguments, leaving mBuffer positioned at the
+ // beginning of first argument. Return 0 on EOF.
template<class FailFn>
int getCount(FailFn fail_fn) {
mLinesLeft = 1;
@@ -451,11 +452,14 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
(CREATE_ERROR("Write unexpectedly returned short: %d < 5", res));
}
}
- // Clear buffer and get count from next command.
- n_buffer->clear();
for (;;) {
+ // Clear buffer and get count from next command.
+ n_buffer->clear();
// Poll isn't strictly necessary for now. But without it, disconnect is hard to detect.
int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */));
+ if (poll_res < 0) {
+ fail_fn_z(CREATE_ERROR("Poll failed: %d: %s", errno, strerror(errno)));
+ }
if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) {
if (n_buffer->getCount(fail_fn_z) != 0) {
break;
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 3887dd7a753f..9ca1849dedc2 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -99,6 +99,7 @@ message SecureSettingsProto {
optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto accessibility_force_invert_color_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto accessibility_magnification_two_finger_triple_tap_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto qs_targets = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Accessibility accessibility = 2;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dd93586c340b..c6a241f2fa62 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4806,6 +4806,13 @@
<permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME"
android:protectionLevel="signature" />
+ <!-- @FlaggedApi("com.android.server.accessibility.motion_event_observing")
+ @hide
+ @TestApi
+ Allows an accessibility service to observe motion events without consuming them. -->
+ <permission android:name="android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING"
+ android:protectionLevel="signature" />
+
<!-- @hide Allows an application to collect frame statistics -->
<permission android:name="android.permission.FRAME_STATS"
android:protectionLevel="signature" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e1c1a42eed81..5cfb1a3e44ba 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9802,6 +9802,17 @@
<attr name="supportedTypes" format="reference" />
</declare-styleable>
+ <!-- Use <code>tv-ad-service</code> as the root tag of the XML resource that describes a
+ android.media.tv.ad.TvAdService, which is referenced from its
+ android.media.tv.ad.TvAdService#SERVICE_META_DATA meta-data entry. Described here
+ are the attributes that can be included in that tag. -->
+ <declare-styleable name="TvAdService">
+ <!-- The advertisement types that the TV ad service supports.
+ Reference to a string array resource that describes the supported types,
+ e.g. linear, overlay. -->
+ <attr name="adServiceTypes" format="reference" />
+ </declare-styleable>
+
<!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the
XML resource that describes TV content rating of a {@link android.media.tv.TvInputService},
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bf8e55fd986f..d0de5f0e4104 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4255,6 +4255,9 @@
-->
<bool name="config_wallpaperTopApp">false</bool>
+ <!-- True if the device supports dVRR -->
+ <bool name="config_supportsDvrr">false</bool>
+
<!-- True if the device supports at least one form of multi-window.
E.g. freeform, split-screen, picture-in-picture. -->
<bool name="config_supportsMultiWindow">true</bool>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index f10e7f8c337e..540967d28d9b 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -117,6 +117,8 @@
<public name="isVirtualDeviceOnly"/>
<!-- @FlaggedApi("android.content.pm.sdk_lib_independence") -->
<public name="optional"/>
+ <!-- @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") -->
+ <public name="adServiceTypes" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1f6ac80a133c..4596ca74bf8f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5252,6 +5252,8 @@
<!-- Zen mode - name of default automatic calendar time-based rule that is triggered every night (when sleeping). [CHAR LIMIT=40] -->
<string name="zen_mode_default_every_night_name">Sleeping</string>
+ <!-- Zen mode - Trigger description of the rule, indicating which app owns it. [CHAR_LIMIT=100] -->
+ <string name="zen_mode_implicit_trigger_description">Managed by <xliff:g id="app_name">%1$s</xliff:g></string>
<!-- Zen mode - Condition summary when a rule is activated due to a call to setInterruptionFilter(). [CHAR_LIMIT=NONE] -->
<string name="zen_mode_implicit_activated">On</string>
<!-- Zen mode - Condition summary when a rule is deactivated due to a call to setInterruptionFilter(). [CHAR_LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5791ddb8addf..ef272ee8bef1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -404,6 +404,7 @@
<java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />
<java-symbol type="bool" name="config_freeformWindowManagement" />
<java-symbol type="bool" name="config_supportsBubble" />
+ <java-symbol type="bool" name="config_supportsDvrr" />
<java-symbol type="bool" name="config_supportsMultiWindow" />
<java-symbol type="bool" name="config_supportsSplitScreenMultiWindow" />
<java-symbol type="bool" name="config_supportsMultiDisplay" />
@@ -2586,6 +2587,7 @@
<java-symbol type="string" name="zen_mode_default_weekends_name" />
<java-symbol type="string" name="zen_mode_default_events_name" />
<java-symbol type="string" name="zen_mode_default_every_night_name" />
+ <java-symbol type="string" name="zen_mode_implicit_trigger_description" />
<java-symbol type="string" name="zen_mode_implicit_activated" />
<java-symbol type="string" name="zen_mode_implicit_deactivated" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 6706c916a0e2..1a3ec27418a6 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -7,19 +7,35 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
-android_test {
- name: "FrameworksCoreTests",
-
+filegroup {
+ name: "FrameworksCoreTests-aidl",
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
"src/**/I*.aidl",
+ "aidl/**/I*.aidl",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "FrameworksCoreTests-helpers",
+ srcs: [
"DisabledTestApp/src/**/*.java",
"EnabledTestApp/src/**/*.java",
"BinderProxyCountingTestApp/src/**/*.java",
"BinderProxyCountingTestService/src/**/*.java",
"BinderDeathRecipientHelperApp/src/**/*.java",
- "aidl/**/I*.aidl",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+android_test {
+ name: "FrameworksCoreTests",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ":FrameworksCoreTests-aidl",
+ ":FrameworksCoreTests-helpers",
":FrameworksCoreTestDoubles-sources",
],
@@ -177,17 +193,29 @@ android_ravenwood_test {
"androidx.annotation_annotation",
"androidx.test.rules",
"androidx.test.ext.junit",
+ "androidx.test.uiautomator_uiautomator",
+ "compatibility-device-util-axt",
+ "flag-junit",
"mockito_ravenwood",
"platform-test-annotations",
"flag-junit",
+ "testng",
],
srcs: [
- "src/android/os/BuildTest.java",
- "src/android/os/FileUtilsTest.java",
+ "src/android/os/**/*.java",
+ "src/com/android/internal/os/**/*.java",
"src/android/util/**/*.java",
"src/com/android/internal/os/LongArrayMultiStateCounterTest.java",
"src/com/android/internal/util/**/*.java",
- "testdoubles/src/com/android/internal/util/**/*.java",
+ "src/com/android/internal/power/EnergyConsumerStatsTest.java",
+ ":FrameworksCoreTests{.aapt.srcjar}",
+ ":FrameworksCoreTests-aidl",
+ ":FrameworksCoreTests-helpers",
+ ":FrameworksCoreTestDoubles-sources",
],
+ aidl: {
+ generate_get_transaction_name: true,
+ local_include_dirs: ["aidl"],
+ },
auto_gen_config: true,
}
diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
index ba2ea88e8e01..1925588e8904 100644
--- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -19,15 +19,20 @@ package android.app;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.google.common.base.Strings;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +43,9 @@ import java.lang.reflect.Field;
public class AutomaticZenRuleTest {
private static final String CLASS = "android.app.AutomaticZenRule";
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Test
public void testLongFields_inConstructor() {
String longString = Strings.repeat("A", 65536);
@@ -100,6 +108,7 @@ public class AutomaticZenRuleTest {
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
public void testLongInputsFromParcel() {
// Create a rule with long fields, set directly via reflection so that we can confirm that
// a rule with too-long fields that comes in via a parcel has its fields truncated directly.
@@ -152,6 +161,69 @@ public class AutomaticZenRuleTest {
fromParcel.getOwner().getPackageName().length());
assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
fromParcel.getOwner().getClassName().length());
- assertEquals(AutomaticZenRule.MAX_DESC_LENGTH, rule.getTriggerDescription().length());
+ assertEquals(AutomaticZenRule.MAX_DESC_LENGTH, fromParcel.getTriggerDescription().length());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void builderConstructor_nullInputs_throws() {
+ assertThrows(NullPointerException.class,
+ () -> new AutomaticZenRule.Builder(null, Uri.parse("condition")));
+ assertThrows(NullPointerException.class,
+ () -> new AutomaticZenRule.Builder("name", null));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_builderWithValidType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
+ .setType(AutomaticZenRule.TYPE_BEDTIME)
+ .build();
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_builderWithoutType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_constructorWithoutType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("rule", new ComponentName("pkg", "cps"),
+ new ComponentName("pkg", "activity"), Uri.parse("condition"), null,
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_invalidType_throws() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+
+ // Set the field via reflection.
+ Field typeField = AutomaticZenRule.class.getDeclaredField("mType");
+ typeField.setAccessible(true);
+ typeField.set(rule, 100);
+
+ assertThrows(IllegalArgumentException.class, rule::validate);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void setType_invalidType_throws() {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+
+ assertThrows(IllegalArgumentException.class, () -> rule.setType(100));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void setTypeBuilder_invalidType_throws() {
+ AutomaticZenRule.Builder builder = new AutomaticZenRule.Builder("rule", Uri.parse("uri"));
+
+ assertThrows(IllegalArgumentException.class, () -> builder.setType(100));
}
}
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index 3768063f2a91..cd6abddc20a1 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -20,9 +20,13 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
import org.junit.After;
+import org.junit.Rule;
import org.junit.Test;
/**
@@ -35,7 +39,10 @@ import org.junit.Test;
* atest FrameworksCoreTests:PropertyInvalidatedCacheTests
*/
@SmallTest
+@IgnoreUnderRavenwood(blockedBy = PropertyInvalidatedCache.class)
public class PropertyInvalidatedCacheTests {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
// Configuration for creating caches
private static final String MODULE = PropertyInvalidatedCache.MODULE_TEST;
diff --git a/core/tests/coretests/src/android/os/AidlTest.java b/core/tests/coretests/src/android/os/AidlTest.java
index d0c3470c4c1f..006828f12156 100644
--- a/core/tests/coretests/src/android/os/AidlTest.java
+++ b/core/tests/coretests/src/android/os/AidlTest.java
@@ -16,23 +16,36 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
import com.google.android.collect.Lists;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
import java.util.List;
-public class AidlTest extends TestCase {
+@IgnoreUnderRavenwood(blockedBy = Parcel.class)
+public class AidlTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private IAidlTest mRemote;
private AidlObject mLocal;
private NonAutoGeneratedObject mNonAutoGenerated;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
mLocal = new AidlObject();
mRemote = IAidlTest.Stub.asInterface(mLocal);
mNonAutoGenerated = new NonAutoGeneratedObject("NonAutoGeneratedObject");
@@ -212,12 +225,14 @@ public class AidlTest extends TestCase {
}
}
+ @Test
@SmallTest
public void testInt() throws Exception {
int result = mRemote.intMethod(42);
assertEquals(42, result);
}
+ @Test
@SmallTest
public void testParcelableIn() throws Exception {
TestParcelable arg = new TestParcelable(43, "hi");
@@ -228,6 +243,7 @@ public class AidlTest extends TestCase {
assertEquals(44, result.mAnInt);
}
+ @Test
@SmallTest
public void testParcelableOut() throws Exception {
TestParcelable arg = new TestParcelable(43, "hi");
@@ -236,6 +252,7 @@ public class AidlTest extends TestCase {
assertEquals(44, arg.mAnInt);
}
+ @Test
@SmallTest
public void testParcelableInOut() throws Exception {
TestParcelable arg = new TestParcelable(43, "hi");
@@ -244,6 +261,7 @@ public class AidlTest extends TestCase {
assertEquals(44, arg.mAnInt);
}
+ @Test
@SmallTest
public void testListParcelableLonger() throws Exception {
List<TestParcelable> list = Lists.newArrayList();
@@ -268,6 +286,7 @@ public class AidlTest extends TestCase {
assertNotSame(list.get(1), list.get(2));
}
+ @Test
@SmallTest
public void testListParcelableShorter() throws Exception {
List<TestParcelable> list = Lists.newArrayList();
@@ -290,6 +309,7 @@ public class AidlTest extends TestCase {
assertNotSame(list.get(0), list.get(1));
}
+ @Test
@SmallTest
public void testArrays() throws Exception {
// boolean
@@ -363,14 +383,14 @@ public class AidlTest extends TestCase {
float[] fr = mRemote.floatArray(f0, f1, f2);
assertEquals(1, fr.length);
- assertEquals(90.1f, fr[0]);
+ assertEquals(90.1f, fr[0], 0.0f);
- assertEquals(90.1f, f1[0]);
+ assertEquals(90.1f, f1[0], 0.0f);
assertEquals(0f, f1[1], 0.0f);
- assertEquals(90.1f, f2[0]);
- assertEquals(90.5f, f2[1]);
- assertEquals(90.6f, f2[2]);
+ assertEquals(90.1f, f2[0], 0.0f);
+ assertEquals(90.5f, f2[1], 0.0f);
+ assertEquals(90.6f, f2[2], 0.0f);
// double
double[] d0 = new double[]{100.1};
@@ -379,14 +399,14 @@ public class AidlTest extends TestCase {
double[] dr = mRemote.doubleArray(d0, d1, d2);
assertEquals(1, dr.length);
- assertEquals(100.1, dr[0]);
+ assertEquals(100.1, dr[0], 0.0);
- assertEquals(100.1, d1[0]);
+ assertEquals(100.1, d1[0], 0.0);
assertEquals(0, d1[1], 0.0);
- assertEquals(100.1, d2[0]);
- assertEquals(100.5, d2[1]);
- assertEquals(100.6, d2[2]);
+ assertEquals(100.1, d2[0], 0.0);
+ assertEquals(100.5, d2[1], 0.0);
+ assertEquals(100.6, d2[2], 0.0);
// String
String[] s0 = new String[]{"s0[0]"};
@@ -405,6 +425,7 @@ public class AidlTest extends TestCase {
assertEquals("s2[2]", s2[2]);
}
+ @Test
@SmallTest
public void testVoidSecurityException() throws Exception {
boolean good = false;
@@ -416,6 +437,7 @@ public class AidlTest extends TestCase {
assertEquals(good, true);
}
+ @Test
@SmallTest
public void testIntSecurityException() throws Exception {
boolean good = false;
@@ -427,6 +449,7 @@ public class AidlTest extends TestCase {
assertEquals(good, true);
}
+ @Test
@SmallTest
public void testGetTransactionNameAutoGenerated() throws Exception {
assertEquals(15, mLocal.getMaxTransactionId());
@@ -446,6 +469,7 @@ public class AidlTest extends TestCase {
mLocal.getTransactionTraceName(IAidlTest.Stub.TRANSACTION_parcelableIn));
}
+ @Test
@SmallTest
public void testGetTransactionNameNonAutoGenerated() throws Exception {
assertEquals(0, mNonAutoGenerated.getMaxTransactionId());
diff --git a/core/tests/coretests/src/android/os/BinderDeathRecipientTest.java b/core/tests/coretests/src/android/os/BinderDeathRecipientTest.java
index 2cce43f70774..eff52f0dc4e2 100644
--- a/core/tests/coretests/src/android/os/BinderDeathRecipientTest.java
+++ b/core/tests/coretests/src/android/os/BinderDeathRecipientTest.java
@@ -25,6 +25,8 @@ import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -36,6 +38,7 @@ import com.android.frameworks.coretests.bdr_helper_app.TestCommsReceiver;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,6 +55,7 @@ import java.util.concurrent.atomic.AtomicReference;
* Tests functionality of {@link android.os.IBinder.DeathRecipient} callbacks.
*/
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
public class BinderDeathRecipientTest {
private static final String TAG = BinderDeathRecipientTest.class.getSimpleName();
private static final String TEST_PACKAGE_NAME_1 =
@@ -59,6 +63,9 @@ public class BinderDeathRecipientTest {
private static final String TEST_PACKAGE_NAME_2 =
"com.android.frameworks.coretests.bdr_helper_app2";
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private Context mContext;
private Handler mHandler;
private ActivityManager mActivityManager;
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index 2089c6cf89c9..bcd9521019e4 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -24,6 +24,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -35,7 +37,8 @@ import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
-import org.junit.BeforeClass;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,6 +74,7 @@ import java.util.function.Consumer;
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
public class BinderProxyCountingTest {
private static final String TAG = BinderProxyCountingTest.class.getSimpleName();
@@ -107,11 +111,14 @@ public class BinderProxyCountingTest {
};
private static int sTestPkgUid;
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
/**
* Setup any common data for the upcoming tests.
*/
- @BeforeClass
- public static void setUpOnce() throws Exception {
+ @Before
+ public void setUp() throws Exception {
sContext = InstrumentationRegistry.getContext();
sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_APP_PKG, 0);
((ActivityManager) sContext.getSystemService(Context.ACTIVITY_SERVICE)).killUid(sTestPkgUid,
diff --git a/core/tests/coretests/src/android/os/BinderProxyTest.java b/core/tests/coretests/src/android/os/BinderProxyTest.java
index 3567d17ea874..a903ed91cb3d 100644
--- a/core/tests/coretests/src/android/os/BinderProxyTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyTest.java
@@ -16,19 +16,34 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.test.AndroidTestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-public class BinderProxyTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = PowerManager.class)
+public class BinderProxyTest {
private static class CountingListener implements Binder.ProxyTransactListener {
int mStartedCount;
int mEndedCount;
@@ -43,17 +58,22 @@ public class BinderProxyTest extends AndroidTestCase {
}
};
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ private Context mContext;
private PowerManager mPowerManager;
/**
* Setup any common data for the upcoming tests.
*/
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
}
+ @Test
@MediumTest
public void testNoListener() throws Exception {
CountingListener listener = new CountingListener();
@@ -66,6 +86,7 @@ public class BinderProxyTest extends AndroidTestCase {
assertEquals(0, listener.mEndedCount);
}
+ @Test
@MediumTest
public void testListener() throws Exception {
CountingListener listener = new CountingListener();
@@ -77,6 +98,7 @@ public class BinderProxyTest extends AndroidTestCase {
assertEquals(1, listener.mEndedCount);
}
+ @Test
@MediumTest
public void testSessionPropagated() throws Exception {
Binder.setProxyTransactListener(new Binder.ProxyTransactListener() {
@@ -95,6 +117,7 @@ public class BinderProxyTest extends AndroidTestCase {
private IBinder mRemoteBinder = null;
+ @Test
@MediumTest
public void testGetExtension() throws Exception {
final CountDownLatch bindLatch = new CountDownLatch(1);
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
index 02f87901318d..6c8b69fc9c5c 100644
--- a/core/tests/coretests/src/android/os/BinderTest.java
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -16,21 +16,35 @@
package android.os;
-import androidx.test.filters.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.testng.Assert.assertThrows;
-import junit.framework.TestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
-import static org.testng.Assert.assertThrows;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
-public class BinderTest extends TestCase {
+@IgnoreUnderRavenwood(blockedBy = WorkSource.class)
+public class BinderTest {
private static final int UID = 100;
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Test
@SmallTest
public void testSetWorkSource() throws Exception {
Binder.setCallingWorkSourceUid(UID);
assertEquals(UID, Binder.getCallingWorkSourceUid());
}
+ @Test
@SmallTest
public void testClearWorkSource() throws Exception {
Binder.setCallingWorkSourceUid(UID);
@@ -38,6 +52,7 @@ public class BinderTest extends TestCase {
assertEquals(-1, Binder.getCallingWorkSourceUid());
}
+ @Test
@SmallTest
public void testRestoreWorkSource() throws Exception {
Binder.setCallingWorkSourceUid(UID);
@@ -46,11 +61,13 @@ public class BinderTest extends TestCase {
assertEquals(UID, Binder.getCallingWorkSourceUid());
}
+ @Test
@SmallTest
public void testGetCallingUidOrThrow_throws() throws Exception {
assertThrows(IllegalStateException.class, () -> Binder.getCallingUidOrThrow());
}
+ @Test
@SmallTest
public void testGetExtension() throws Exception {
Binder binder = new Binder();
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
index 48c9df65da61..4172bffe100c 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
@@ -16,21 +16,42 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.test.AndroidTestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.File;
import java.io.IOException;
/**
* Test whether Binder calls inherit thread priorities correctly.
*/
-public class BinderThreadPriorityTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
+public class BinderThreadPriorityTest {
private static final String TAG = "BinderThreadPriorityTest";
+
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ private Context mContext;
private IBinderThreadPriorityService mService;
private int mSavedPriority;
@@ -55,12 +76,11 @@ public class BinderThreadPriorityTest extends AndroidTestCase {
private static void fail() { throw new RuntimeException("unimplemented"); }
}
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- getContext().bindService(
- new Intent(getContext(), BinderThreadPriorityService.class),
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mContext.bindService(
+ new Intent(mContext, BinderThreadPriorityService.class),
mConnection, Context.BIND_AUTO_CREATE);
synchronized (this) {
@@ -80,8 +100,8 @@ public class BinderThreadPriorityTest extends AndroidTestCase {
Log.i(TAG, "Saved priority: " + mSavedPriority);
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
// HACK -- see bug 2665914 -- setThreadPriority() doesn't always set the
// scheduler group reliably unless we start out with background priority.
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -89,8 +109,7 @@ public class BinderThreadPriorityTest extends AndroidTestCase {
assertEquals(mSavedPriority, Process.getThreadPriority(Process.myTid()));
assertEquals(expectedSchedulerGroup(mSavedPriority), getSchedulerGroup());
- getContext().unbindService(mConnection);
- super.tearDown();
+ mContext.unbindService(mConnection);
}
public static String getSchedulerGroup() {
@@ -111,6 +130,7 @@ public class BinderThreadPriorityTest extends AndroidTestCase {
return "/";
}
+ @Test
public void testPassPriorityToService() throws Exception {
for (int prio = 19; prio >= -20; prio--) {
Process.setThreadPriority(prio);
@@ -125,6 +145,7 @@ public class BinderThreadPriorityTest extends AndroidTestCase {
}
}
+ @Test
public void testCallBackFromServiceWithPriority() throws Exception {
for (int prio = -20; prio <= 19; prio++) {
final int expected = prio;
diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
index b14c88f7341e..552066c92931 100644
--- a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
@@ -19,11 +19,14 @@ package android.os;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -33,6 +36,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,12 +46,16 @@ import org.junit.runner.RunWith;
@LargeTest
@Presubmit
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
public class BinderWorkSourceTest {
private static Context sContext;
private static final int UID = 100;
private static final int SECOND_UID = 200;
private static final int UID_NONE = ThreadLocalWorkSource.UID_NONE;
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private IBinderWorkSourceService mService;
private IBinderWorkSourceNestedService mNestedService;
@@ -71,13 +79,9 @@ public class BinderWorkSourceTest {
}
};
- @BeforeClass
- public static void setUpOnce() throws Exception {
- sContext = InstrumentationRegistry.getContext();
- }
-
@Before
public void setUp() throws Exception {
+ sContext = InstrumentationRegistry.getContext();
sContext.bindService(
new Intent(sContext, BinderWorkSourceService.class),
mConnection, Context.BIND_AUTO_CREATE);
diff --git a/core/tests/coretests/src/android/os/BroadcasterTest.java b/core/tests/coretests/src/android/os/BroadcasterTest.java
index b4c47af93355..7829457109cd 100644
--- a/core/tests/coretests/src/android/os/BroadcasterTest.java
+++ b/core/tests/coretests/src/android/os/BroadcasterTest.java
@@ -16,16 +16,26 @@
package android.os;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
-import junit.framework.TestCase;
+@RunWith(AndroidJUnit4.class)
+public class BroadcasterTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
-public class BroadcasterTest extends TestCase {
private static final int MESSAGE_A = 23234;
private static final int MESSAGE_B = 3;
private static final int MESSAGE_C = 14;
private static final int MESSAGE_D = 95;
+ @Test
@MediumTest
public void test1() throws Exception {
/*
@@ -103,6 +113,7 @@ public class BroadcasterTest extends TestCase {
}
}
+ @Test
@MediumTest
public void test2() throws Exception {
/*
@@ -112,6 +123,7 @@ public class BroadcasterTest extends TestCase {
tester.doTest(1000);
}
+ @Test
@MediumTest
public void test3() throws Exception {
/*
@@ -121,6 +133,7 @@ public class BroadcasterTest extends TestCase {
tester.doTest(1000);
}
+ @Test
@MediumTest
public void test4() throws Exception {
/*
@@ -156,6 +169,7 @@ public class BroadcasterTest extends TestCase {
tester.doTest(1000);
}
+ @Test
@MediumTest
public void test5() throws Exception {
/*
@@ -191,6 +205,7 @@ public class BroadcasterTest extends TestCase {
tester.doTest(1000);
}
+ @Test
@MediumTest
public void test6() throws Exception {
/*
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index a3bda8b23f30..e7b5dff60110 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -23,13 +23,16 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.Log;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +48,9 @@ import java.util.Objects;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class BundleTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private Log.TerribleFailureHandler mWtfHandler;
@After
@@ -115,6 +121,7 @@ public class BundleTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
public void testCreateFromParcel() throws Exception {
boolean withFd;
Parcel p;
@@ -295,6 +302,7 @@ public class BundleTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void kindofEquals_lazyValuesAndDifferentClassLoaders_returnsFalse() {
Parcelable p1 = new CustomParcelable(13, "Tiramisu");
Parcelable p2 = new CustomParcelable(13, "Tiramisu");
@@ -350,6 +358,7 @@ public class BundleTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void readWriteLengthMismatch_logsWtf() throws Exception {
mWtfHandler = Log.setWtfHandler((tag, e, system) -> {
throw new RuntimeException(e);
@@ -364,6 +373,7 @@ public class BundleTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void getParcelable_whenThrowingAndNotDefusing_throws() throws Exception {
Bundle.setShouldDefuse(false);
Bundle bundle = new Bundle();
@@ -376,6 +386,7 @@ public class BundleTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void getParcelable_whenThrowingAndDefusing_returnsNull() throws Exception {
Bundle.setShouldDefuse(true);
Bundle bundle = new Bundle();
@@ -391,6 +402,7 @@ public class BundleTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void getParcelable_whenThrowingAndDefusing_leavesElement() throws Exception {
Bundle.setShouldDefuse(true);
Bundle bundle = new Bundle();
diff --git a/core/tests/coretests/src/android/os/CancellationSignalBeamerTest.java b/core/tests/coretests/src/android/os/CancellationSignalBeamerTest.java
index 42c97f3876a6..c2cea0a2c286 100644
--- a/core/tests/coretests/src/android/os/CancellationSignalBeamerTest.java
+++ b/core/tests/coretests/src/android/os/CancellationSignalBeamerTest.java
@@ -22,6 +22,8 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.CancellationSignalBeamer.Receiver;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.PollingCheck;
import android.util.PollingCheck.PollingCheckCondition;
@@ -29,6 +31,8 @@ import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,11 +44,20 @@ import java.util.concurrent.CountDownLatch;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@IgnoreUnderRavenwood(blockedBy = CancellationSignalBeamer.class)
public class CancellationSignalBeamerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
- private CancellationSignal mSenderSignal = new CancellationSignal();
+ private CancellationSignal mSenderSignal;
private CancellationSignal mReceivedSignal;
- private Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mSenderSignal = new CancellationSignal();
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ }
@Test
public void testBeam_null() {
@@ -208,17 +221,22 @@ public class CancellationSignalBeamerTest {
mReceivedSignal = mReceiver.unbeam(cancellationSignalToken);
}
- private final Sender mSender = new Sender() {
- @Override
- public void onCancel(IBinder token) {
- mReceiver.cancel(token);
- }
+ private Sender mSender;
+ private Receiver mReceiver;
- @Override
- public void onForget(IBinder token) {
- mReceiver.forget(token);
- }
- };
+ @Before
+ public void setUpSenderReceiver() {
+ mSender = new Sender() {
+ @Override
+ public void onCancel(IBinder token) {
+ mReceiver.cancel(token);
+ }
- private final Receiver mReceiver = new Receiver(false);
+ @Override
+ public void onForget(IBinder token) {
+ mReceiver.forget(token);
+ }
+ };
+ mReceiver = new Receiver(false);
+ }
}
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index ef38cdec0d63..1aa263f13d92 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -28,12 +28,15 @@ import static org.junit.Assert.assertEquals;
import android.content.Context;
import android.os.storage.StorageManager;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,7 +46,11 @@ import java.util.UUID;
import java.util.function.BiFunction;
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = Environment.class)
public class EnvironmentTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private File dir;
private static Context getContext() {
diff --git a/core/tests/coretests/src/android/os/FileBridgeTest.java b/core/tests/coretests/src/android/os/FileBridgeTest.java
index 708bfa6ece2e..726670b4d625 100644
--- a/core/tests/coretests/src/android/os/FileBridgeTest.java
+++ b/core/tests/coretests/src/android/os/FileBridgeTest.java
@@ -19,12 +19,25 @@ package android.os;
import static android.os.ParcelFileDescriptor.MODE_CREATE;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import android.os.FileBridge.FileBridgeOutputStream;
-import android.test.AndroidTestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.test.MoreAsserts;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
import libcore.io.Streams;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -32,18 +45,20 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Random;
-public class FileBridgeTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
+public class FileBridgeTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private File file;
private ParcelFileDescriptor outputFile;
private FileBridge bridge;
private FileBridgeOutputStream client;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- file = getContext().getFileStreamPath("meow.dat");
+ @Before
+ public void setUp() throws Exception {
+ file = File.createTempFile("meow", "dat");
file.delete();
outputFile = ParcelFileDescriptor.open(file, MODE_CREATE | MODE_READ_WRITE);
@@ -54,8 +69,8 @@ public class FileBridgeTest extends AndroidTestCase {
client = new FileBridgeOutputStream(bridge.getClientSocket());
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
outputFile.close();
file.delete();
}
@@ -76,17 +91,20 @@ public class FileBridgeTest extends AndroidTestCase {
MoreAsserts.assertEquals(expected, Streams.readFully(new FileInputStream(file)));
}
+ @Test
public void testNoWriteNoSync() throws Exception {
assertOpen();
closeAndAssertClosed();
}
+ @Test
public void testNoWriteSync() throws Exception {
assertOpen();
client.flush();
closeAndAssertClosed();
}
+ @Test
public void testWriteNoSync() throws Exception {
assertOpen();
client.write("meow".getBytes(StandardCharsets.UTF_8));
@@ -94,6 +112,7 @@ public class FileBridgeTest extends AndroidTestCase {
assertContents("meow".getBytes(StandardCharsets.UTF_8));
}
+ @Test
public void testWriteSync() throws Exception {
assertOpen();
client.write("cake".getBytes(StandardCharsets.UTF_8));
@@ -102,6 +121,7 @@ public class FileBridgeTest extends AndroidTestCase {
assertContents("cake".getBytes(StandardCharsets.UTF_8));
}
+ @Test
public void testWriteSyncWrite() throws Exception {
assertOpen();
client.write("meow".getBytes(StandardCharsets.UTF_8));
@@ -111,6 +131,7 @@ public class FileBridgeTest extends AndroidTestCase {
assertContents("meowcake".getBytes(StandardCharsets.UTF_8));
}
+ @Test
public void testEmptyWrite() throws Exception {
assertOpen();
client.write(new byte[0]);
@@ -118,6 +139,7 @@ public class FileBridgeTest extends AndroidTestCase {
assertContents(new byte[0]);
}
+ @Test
public void testWriteAfterClose() throws Exception {
assertOpen();
client.write("meow".getBytes(StandardCharsets.UTF_8));
@@ -130,6 +152,7 @@ public class FileBridgeTest extends AndroidTestCase {
assertContents("meow".getBytes(StandardCharsets.UTF_8));
}
+ @Test
public void testRandomWrite() throws Exception {
final Random r = new Random();
final ByteArrayOutputStream result = new ByteArrayOutputStream();
@@ -146,6 +169,7 @@ public class FileBridgeTest extends AndroidTestCase {
assertContents(result.toByteArray());
}
+ @Test
public void testGiantWrite() throws Exception {
final byte[] test = new byte[263401];
new Random().nextBytes(test);
diff --git a/core/tests/coretests/src/android/os/FileObserverTest.java b/core/tests/coretests/src/android/os/FileObserverTest.java
index ece7645b7389..3cd8045c32cb 100644
--- a/core/tests/coretests/src/android/os/FileObserverTest.java
+++ b/core/tests/coretests/src/android/os/FileObserverTest.java
@@ -16,21 +16,37 @@
package android.os;
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.Log;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.File;
import java.io.FileOutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-public class FileObserverTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = FileObserver.class)
+public class FileObserverTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private Observer mObserver;
private File mTestFile;
@@ -57,18 +73,19 @@ public class FileObserverTest extends AndroidTestCase {
}
}
- @Override
- protected void setUp() throws Exception {
+ @Before
+ public void setUp() throws Exception {
mTestFile = File.createTempFile(".file_observer_test", ".txt");
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
if (mTestFile != null && mTestFile.exists()) {
mTestFile.delete();
}
}
+ @Test
@MediumTest
public void testRun() throws Exception {
// make file changes and wait for them
diff --git a/core/tests/coretests/src/android/os/HandlerThreadTest.java b/core/tests/coretests/src/android/os/HandlerThreadTest.java
index 93cfc40d555e..0bac1c728f3b 100644
--- a/core/tests/coretests/src/android/os/HandlerThreadTest.java
+++ b/core/tests/coretests/src/android/os/HandlerThreadTest.java
@@ -16,18 +16,35 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
-public class HandlerThreadTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class HandlerThreadTest {
private static final int TEST_WHAT = 1;
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private boolean mGotMessage = false;
private int mGotMessageWhat = -1;
private volatile boolean mDidSetup = false;
private volatile int mLooperTid = -1;
-
+
+ @Test
@MediumTest
public void testHandlerThread() throws Exception {
HandlerThread th1 = new HandlerThread("HandlerThreadTest") {
diff --git a/core/tests/coretests/src/android/os/IdleHandlerTest.java b/core/tests/coretests/src/android/os/IdleHandlerTest.java
index d8886c97838e..864466329389 100644
--- a/core/tests/coretests/src/android/os/IdleHandlerTest.java
+++ b/core/tests/coretests/src/android/os/IdleHandlerTest.java
@@ -17,12 +17,19 @@
package android.os;
import android.os.MessageQueue.IdleHandler;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
-public class IdleHandlerTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class IdleHandlerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private static class BaseTestHandler extends TestHandlerThread {
Handler mHandler;
@@ -54,6 +61,7 @@ public class IdleHandlerTest extends TestCase {
}
}
+ @Test
@MediumTest
public void testOneShotFirst() throws Exception {
TestHandlerThread tester = new BaseTestHandler() {
@@ -88,6 +96,7 @@ public class IdleHandlerTest extends TestCase {
tester.doTest(1000);
}
+ @Test
@MediumTest
public void testOneShotLater() throws Exception {
TestHandlerThread tester = new BaseTestHandler() {
@@ -125,6 +134,7 @@ public class IdleHandlerTest extends TestCase {
}
+ @Test
@MediumTest
public void testRepeatedFirst() throws Exception {
TestHandlerThread tester = new BaseTestHandler() {
@@ -159,6 +169,7 @@ public class IdleHandlerTest extends TestCase {
tester.doTest(1000);
}
+ @Test
@MediumTest
public void testRepeatedLater() throws Exception {
TestHandlerThread tester = new BaseTestHandler() {
diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
index 34712ce54e0f..b03fd6485786 100644
--- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java
+++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
@@ -17,12 +17,14 @@
package android.os;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertSame;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import org.junit.After;
+import org.junit.Rule;
import org.junit.Test;
/**
@@ -35,7 +37,10 @@ import org.junit.Test;
* atest FrameworksCoreTests:IpcDataCacheTest
*/
@SmallTest
+@IgnoreUnderRavenwood(blockedBy = IpcDataCache.class)
public class IpcDataCacheTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
// Configuration for creating caches
private static final String MODULE = IpcDataCache.MODULE_TEST;
diff --git a/core/tests/coretests/src/android/os/LocaleListTest.java b/core/tests/coretests/src/android/os/LocaleListTest.java
index 88fc8267f5b2..0025e3a3c454 100644
--- a/core/tests/coretests/src/android/os/LocaleListTest.java
+++ b/core/tests/coretests/src/android/os/LocaleListTest.java
@@ -16,13 +16,29 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Locale;
-public class LocaleListTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = LocaleList.class)
+public class LocaleListTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Test
@SmallTest
public void testConstructor() throws Exception {
LocaleList ll;
@@ -51,6 +67,7 @@ public class LocaleListTest extends TestCase {
assertEquals("fr,de", ll.toLanguageTags());
}
+ @Test
@SmallTest
public void testConstructor_nullThrows() throws Exception {
try {
@@ -61,6 +78,7 @@ public class LocaleListTest extends TestCase {
}
}
+ @Test
@SmallTest
public void testGetDefault_localeSetDefaultCalledButNoChangeNecessary() throws Exception {
final Locale originalLocale = Locale.getDefault();
@@ -82,6 +100,7 @@ public class LocaleListTest extends TestCase {
LocaleList.setDefault(originalLocaleList, originalLocaleIndex);
}
+ @Test
@SmallTest
public void testIntersection() {
LocaleList localesWithN = new LocaleList(
diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java
index 05c2995fa158..a69542479afc 100644
--- a/core/tests/coretests/src/android/os/MemoryFileTest.java
+++ b/core/tests/coretests/src/android/os/MemoryFileTest.java
@@ -16,11 +16,21 @@
package android.os;
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -29,7 +39,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-public class MemoryFileTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = MemoryFile.class)
+public class MemoryFileTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private void compareBuffers(byte[] buffer1, byte[] buffer2, int length) throws Exception {
for (int i = 0; i < length; i++) {
@@ -44,6 +58,8 @@ public class MemoryFileTest extends AndroidTestCase {
*/
// Flaky test - temporarily suppress from large suite for now
// @LargeTest
+ @Test
+ @Ignore("Flaky test")
public void testPurge() throws Exception {
List<MemoryFile> files = new ArrayList<MemoryFile>();
try {
@@ -70,6 +86,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
}
+ @Test
@SmallTest
public void testRun() throws Exception {
MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
@@ -102,6 +119,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
// http://code.google.com/p/android/issues/detail?id=11415
+ @Test
public void testOutputStreamAdvances() throws IOException {
MemoryFile file = new MemoryFile("MemoryFileTest", 10);
@@ -142,24 +160,28 @@ public class MemoryFileTest extends AndroidTestCase {
}
}
+ @Test
@SmallTest
public void testReadNegativeOffset() throws Exception {
readIndexOutOfBoundsException(-1, 5,
"read() with negative offset should throw IndexOutOfBoundsException");
}
+ @Test
@SmallTest
public void testReadNegativeCount() throws Exception {
readIndexOutOfBoundsException(5, -1,
"read() with negative length should throw IndexOutOfBoundsException");
}
+ @Test
@SmallTest
public void testReadOffsetOverflow() throws Exception {
readIndexOutOfBoundsException(testString.length + 10, 5,
"read() with offset outside buffer should throw IndexOutOfBoundsException");
}
+ @Test
@SmallTest
public void testReadOffsetCountOverflow() throws Exception {
readIndexOutOfBoundsException(testString.length, 11,
@@ -167,6 +189,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
// Test behavior of read() at end of file
+ @Test
@SmallTest
public void testReadEOF() throws Exception {
MemoryFile file = new MemoryFile("MemoryFileTest", testString.length);
@@ -189,6 +212,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
// Tests that close() is idempotent
+ @Test
@SmallTest
public void testCloseClose() throws Exception {
MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
@@ -199,6 +223,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
// Tests that we can't read from a closed memory file
+ @Test
@SmallTest
public void testCloseRead() throws Exception {
MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
@@ -214,6 +239,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
// Tests that we can't write to a closed memory file
+ @Test
@SmallTest
public void testCloseWrite() throws Exception {
MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
@@ -229,6 +255,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
// Tests that we can't call allowPurging() after close()
+ @Test
@SmallTest
public void testCloseAllowPurging() throws Exception {
MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
@@ -245,6 +272,7 @@ public class MemoryFileTest extends AndroidTestCase {
}
// Tests that we don't leak file descriptors or mmap areas
+ @Test
@LargeTest
public void testCloseLeak() throws Exception {
// open enough memory files that we should run out of
diff --git a/core/tests/coretests/src/android/os/MessageQueueTest.java b/core/tests/coretests/src/android/os/MessageQueueTest.java
index 2c5588e6ed0d..851e61259241 100644
--- a/core/tests/coretests/src/android/os/MessageQueueTest.java
+++ b/core/tests/coretests/src/android/os/MessageQueueTest.java
@@ -16,13 +16,22 @@
package android.os;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.MediumTest;
import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
@Suppress // Failing.
-public class MessageQueueTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class MessageQueueTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private static class BaseTestHandler extends TestHandlerThread {
Handler mHandler;
@@ -61,6 +70,7 @@ public class MessageQueueTest extends TestCase {
}
}
+ @Test
@MediumTest
public void testMessageOrder() throws Exception {
TestHandlerThread tester = new BaseTestHandler() {
@@ -80,6 +90,7 @@ public class MessageQueueTest extends TestCase {
tester.doTest(1000);
}
+ @Test
@MediumTest
public void testAtFrontOfQueue() throws Exception {
TestHandlerThread tester = new BaseTestHandler() {
@@ -141,7 +152,9 @@ public class MessageQueueTest extends TestCase {
}
}
+ @Test
@MediumTest
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testFieldIntegrity() throws Exception {
TestHandlerThread tester = new TestFieldIntegrityHandler() {
@@ -157,7 +170,7 @@ public class MessageQueueTest extends TestCase {
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
- msg.flags = -1;
+ msg.flags = Message.FLAGS_TO_CLEAR_ON_COPY_FROM;
msg.what = 1;
msg.arg1 = 456;
msg.arg2 = 789;
diff --git a/core/tests/coretests/src/android/os/MessengerTest.java b/core/tests/coretests/src/android/os/MessengerTest.java
index 9143ff1d1017..eb6263fe8053 100644
--- a/core/tests/coretests/src/android/os/MessengerTest.java
+++ b/core/tests/coretests/src/android/os/MessengerTest.java
@@ -16,15 +16,31 @@
package android.os;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.test.AndroidTestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
-public class MessengerTest extends AndroidTestCase {
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
+public class MessengerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ private Context mContext;
private Messenger mServiceMessenger;
private ServiceConnection mConnection = new ServiceConnection() {
@@ -86,10 +102,10 @@ public class MessengerTest extends AndroidTestCase {
}
};
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- getContext().bindService(new Intent(mContext, MessengerService.class),
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mContext.bindService(new Intent(mContext, MessengerService.class),
mConnection, Context.BIND_AUTO_CREATE);
synchronized (this) {
while (mServiceMessenger == null) {
@@ -101,15 +117,14 @@ public class MessengerTest extends AndroidTestCase {
}
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- getContext().unbindService(mConnection);
+ @After
+ public void tearDown() throws Exception {
+ mContext.unbindService(mConnection);
}
+ @Test
@MediumTest
public void testSend() {
(new TestThread()).doTest(1000);
-
}
}
diff --git a/core/tests/coretests/src/android/os/OsTests.java b/core/tests/coretests/src/android/os/OsTests.java
deleted file mode 100644
index 08fb945857e9..000000000000
--- a/core/tests/coretests/src/android/os/OsTests.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2006 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.os;
-
-import junit.framework.TestSuite;
-
-public class OsTests {
- public static TestSuite suite() {
- TestSuite suite = new TestSuite(OsTests.class.getName());
-
- suite.addTestSuite(AidlTest.class);
- suite.addTestSuite(BroadcasterTest.class);
- suite.addTestSuite(FileObserverTest.class);
- suite.addTestSuite(IdleHandlerTest.class);
- suite.addTestSuite(MessageQueueTest.class);
- suite.addTestSuite(MessengerTest.class);
- suite.addTestSuite(PatternMatcherTest.class);
-
- return suite;
- }
-}
diff --git a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
index b4e180cf647c..ffeab291e49f 100644
--- a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
+++ b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
@@ -20,11 +20,14 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ArrayMap;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,6 +39,9 @@ import java.util.Map;
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class ParcelNullabilityTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void nullByteArray() {
Parcel p = Parcel.obtain();
@@ -61,6 +67,7 @@ public final class ParcelNullabilityTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void nullCharSequence() {
Parcel p = Parcel.obtain();
p.writeCharSequence(null);
@@ -69,6 +76,7 @@ public final class ParcelNullabilityTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void nullStrongBinder() {
Parcel p = Parcel.obtain();
p.writeStrongBinder(null);
@@ -77,6 +85,7 @@ public final class ParcelNullabilityTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void nullStringInterface() {
Parcel p = Parcel.obtain();
p.writeStrongInterface(null);
diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java
index 4b993fadc1e0..26f6d696768a 100644
--- a/core/tests/coretests/src/android/os/ParcelTest.java
+++ b/core/tests/coretests/src/android/os/ParcelTest.java
@@ -21,22 +21,29 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ParcelTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private static final int WORK_SOURCE_1 = 1000;
private static final int WORK_SOURCE_2 = 1002;
private static final String INTERFACE_TOKEN_1 = "IBinder interface token";
private static final String INTERFACE_TOKEN_2 = "Another IBinder interface token";
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testIsForRpc() {
Parcel p = Parcel.obtain();
assertEquals(false, p.isForRpc());
@@ -44,6 +51,7 @@ public class ParcelTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCallingWorkSourceUidAfterWrite() {
Parcel p = Parcel.obtain();
// Method does not throw if replaceCallingWorkSourceUid is called before requests headers
@@ -64,6 +72,7 @@ public class ParcelTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCallingWorkSourceUidAfterEnforce() {
Parcel p = Parcel.obtain();
p.writeInterfaceToken(INTERFACE_TOKEN_1);
@@ -81,6 +90,7 @@ public class ParcelTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testParcelWithMultipleHeaders() {
Parcel p = Parcel.obtain();
Binder.setCallingWorkSourceUid(WORK_SOURCE_1);
@@ -138,6 +148,7 @@ public class ParcelTest {
}
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testCompareDataInRange_whenSameDataWithBinder() {
Binder binder = new Binder();
Parcel pA = Parcel.obtain();
@@ -297,6 +308,7 @@ public class ParcelTest {
* and 1M length for complex objects are allowed.
*/
@Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
public void testAllocations_whenWithinLimit() {
Binder.setIsDirectlyHandlingTransactionOverride(true);
Parcel p = Parcel.obtain();
diff --git a/core/tests/coretests/src/android/os/PatternMatcherTest.java b/core/tests/coretests/src/android/os/PatternMatcherTest.java
index 82350cd5ffdf..a5e036de6f20 100644
--- a/core/tests/coretests/src/android/os/PatternMatcherTest.java
+++ b/core/tests/coretests/src/android/os/PatternMatcherTest.java
@@ -16,9 +16,10 @@
package android.os;
-import androidx.test.filters.SmallTest;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,7 +27,7 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
@SmallTest
-public class PatternMatcherTest extends TestCase{
+public class PatternMatcherTest {
@Test
public void testAdvancedPatternMatchesAnyToken() {
diff --git a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
index 38ad90f11a23..46f1706c47c7 100644
--- a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
@@ -16,33 +16,48 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
import android.os.PerformanceCollector.PerformanceResultsWriter;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Random;
-public class PerformanceCollectorTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = PerformanceCollector.class)
+public class PerformanceCollectorTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private PerformanceCollector mPerfCollector;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
mPerfCollector = new PerformanceCollector();
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
mPerfCollector = null;
}
+ @Test
@SmallTest
public void testBeginSnapshotNoWriter() throws Exception {
mPerfCollector.beginSnapshot("testBeginSnapshotNoWriter");
@@ -54,6 +69,7 @@ public class PerformanceCollectorTest extends TestCase {
assertEquals(2, snapshot.size());
}
+ @Test
@MediumTest
public void testEndSnapshotNoWriter() throws Exception {
mPerfCollector.beginSnapshot("testEndSnapshotNoWriter");
@@ -63,6 +79,7 @@ public class PerformanceCollectorTest extends TestCase {
verifySnapshotBundle(snapshot);
}
+ @Test
@SmallTest
public void testStartTimingNoWriter() throws Exception {
mPerfCollector.startTiming("testStartTimingNoWriter");
@@ -74,6 +91,7 @@ public class PerformanceCollectorTest extends TestCase {
verifyTimingBundle(measurement, new ArrayList<String>());
}
+ @Test
@SmallTest
public void testAddIterationNoWriter() throws Exception {
mPerfCollector.startTiming("testAddIterationNoWriter");
@@ -83,6 +101,7 @@ public class PerformanceCollectorTest extends TestCase {
verifyIterationBundle(iteration, "timing1");
}
+ @Test
@SmallTest
public void testStopTimingNoWriter() throws Exception {
mPerfCollector.startTiming("testStopTimingNoWriter");
@@ -100,6 +119,7 @@ public class PerformanceCollectorTest extends TestCase {
verifyTimingBundle(timing, labels);
}
+ @Test
@SmallTest
public void testBeginSnapshot() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -114,6 +134,7 @@ public class PerformanceCollectorTest extends TestCase {
assertEquals(2, snapshot.size());
}
+ @Test
@MediumTest
public void testEndSnapshot() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -127,6 +148,7 @@ public class PerformanceCollectorTest extends TestCase {
verifySnapshotBundle(snapshot1);
}
+ @Test
@SmallTest
public void testStartTiming() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -141,6 +163,7 @@ public class PerformanceCollectorTest extends TestCase {
verifyTimingBundle(measurement, new ArrayList<String>());
}
+ @Test
@SmallTest
public void testAddIteration() throws Exception {
mPerfCollector.startTiming("testAddIteration");
@@ -150,6 +173,7 @@ public class PerformanceCollectorTest extends TestCase {
verifyIterationBundle(iteration, "timing5");
}
+ @Test
@SmallTest
public void testStopTiming() throws Exception {
mPerfCollector.startTiming("testStopTiming");
@@ -167,6 +191,7 @@ public class PerformanceCollectorTest extends TestCase {
verifyTimingBundle(timing, labels);
}
+ @Test
@SmallTest
public void testAddMeasurementLong() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -188,6 +213,7 @@ public class PerformanceCollectorTest extends TestCase {
assertEquals(-19354, results.getLong("testAddMeasurementLongNeg"));
}
+ @Test
@SmallTest
public void testAddMeasurementFloat() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -202,13 +228,14 @@ public class PerformanceCollectorTest extends TestCase {
Bundle results = writer.timingResults;
assertEquals(4, results.size());
assertTrue(results.containsKey("testAddMeasurementFloatZero"));
- assertEquals(0.0f, results.getFloat("testAddMeasurementFloatZero"));
+ assertEquals(0.0f, results.getFloat("testAddMeasurementFloatZero"), 0.0f);
assertTrue(results.containsKey("testAddMeasurementFloatPos"));
- assertEquals(348573.345f, results.getFloat("testAddMeasurementFloatPos"));
+ assertEquals(348573.345f, results.getFloat("testAddMeasurementFloatPos"), 0.0f);
assertTrue(results.containsKey("testAddMeasurementFloatNeg"));
- assertEquals(-19354.093f, results.getFloat("testAddMeasurementFloatNeg"));
+ assertEquals(-19354.093f, results.getFloat("testAddMeasurementFloatNeg"), 0.0f);
}
+ @Test
@SmallTest
public void testAddMeasurementString() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -230,6 +257,7 @@ public class PerformanceCollectorTest extends TestCase {
assertEquals("Hello World", results.getString("testAddMeasurementStringNonEmpty"));
}
+ @Test
@MediumTest
public void testSimpleSequence() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -262,6 +290,7 @@ public class PerformanceCollectorTest extends TestCase {
verifyTimingBundle(timing, labels);
}
+ @Test
@MediumTest
public void testLongSequence() throws Exception {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
@@ -348,6 +377,7 @@ public class PerformanceCollectorTest extends TestCase {
* Verify that snapshotting and timing do not interfere w/ each other,
* by staggering calls to snapshot and timing functions.
*/
+ @Test
@MediumTest
public void testOutOfOrderSequence() {
MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index 9b4dec4118a1..12a28446b0e1 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -24,18 +24,25 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNotNull;
import android.os.PerformanceHintManager.Session;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = PerformanceHintManager.class)
public class PerformanceHintManagerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private static final long RATE_1000 = 1000L;
private static final long TARGET_166 = 166L;
private static final long DEFAULT_TARGET_NS = 16666666L;
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index 5d213caf61e6..cb281ff8a6a7 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -17,7 +17,9 @@
package android.os;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -26,28 +28,34 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.os.Flags;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.test.AndroidTestCase;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
-public class PowerManagerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = PowerManager.class)
+public class PowerManagerTest {
private static final String TAG = "PowerManagerTest";
+ private Context mContext;
private PowerManager mPm;
private UiDevice mUiDevice;
private Executor mExec = Executors.newSingleThreadExecutor();
@@ -68,21 +76,27 @@ public class PowerManagerTest extends AndroidTestCase {
String[] keys, String[] values);
static {
- System.loadLibrary("powermanagertest_jni");
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ System.loadLibrary("powermanagertest_jni");
+ }
}
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
// Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect.
@Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isUnderRavenwood() ? null
+ : DeviceFlagsValueProvider.createCheckFlagsRule();
/**
* Setup any common data for the upcoming tests.
*/
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
MockitoAnnotations.initMocks(this);
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mUiDevice.executeShellCommand("cmd thermalservice override-status 0");
}
@@ -100,6 +114,7 @@ public class PowerManagerTest extends AndroidTestCase {
*
* @throws Exception
*/
+ @Test
@SmallTest
public void testPreconditions() throws Exception {
assertNotNull(mPm);
@@ -110,6 +125,7 @@ public class PowerManagerTest extends AndroidTestCase {
*
* @throws Exception
*/
+ @Test
@SmallTest
public void testNewWakeLock() throws Exception {
PowerManager.WakeLock wl = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "FULL_WAKE_LOCK");
@@ -133,6 +149,7 @@ public class PowerManagerTest extends AndroidTestCase {
*
* @throws Exception
*/
+ @Test
@SmallTest
public void testBadNewWakeLock() throws Exception {
final int badFlags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK
@@ -152,6 +169,7 @@ public class PowerManagerTest extends AndroidTestCase {
*
* @throws Exception
*/
+ @Test
@SmallTest
public void testWakeLockWithWorkChains() throws Exception {
PowerManager.WakeLock wakeLock = mPm.newWakeLock(
diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java
index b2ffdc035e8b..310baa371163 100644
--- a/core/tests/coretests/src/android/os/ProcessTest.java
+++ b/core/tests/coretests/src/android/os/ProcessTest.java
@@ -17,12 +17,23 @@
package android.os;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
-public class ProcessTest extends TestCase {
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@IgnoreUnderRavenwood(blockedBy = Process.class)
+public class ProcessTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private static final int BAD_PID = 0;
+ @Test
public void testProcessGetUidFromName() throws Exception {
assertEquals(android.os.Process.SYSTEM_UID, Process.getUidForName("system"));
assertEquals(Process.BLUETOOTH_UID, Process.getUidForName("bluetooth"));
@@ -36,6 +47,7 @@ public class ProcessTest extends TestCase {
Process.getUidForName("u3_a100"));
}
+ @Test
public void testProcessGetUidFromNameFailure() throws Exception {
// Failure cases
assertEquals(-1, Process.getUidForName("u2a_foo"));
@@ -51,6 +63,7 @@ public class ProcessTest extends TestCase {
* Tests getUidForPid() by ensuring that it returns the correct value when the process queried
* doesn't exist.
*/
+ @Test
public void testGetUidForPidInvalidPid() {
assertEquals(-1, Process.getUidForPid(BAD_PID));
}
@@ -59,6 +72,7 @@ public class ProcessTest extends TestCase {
* Tests getParentPid() by ensuring that it returns the correct value when the process queried
* doesn't exist.
*/
+ @Test
public void testGetParentPidInvalidPid() {
assertEquals(-1, Process.getParentPid(BAD_PID));
}
@@ -67,11 +81,13 @@ public class ProcessTest extends TestCase {
* Tests getThreadGroupLeader() by ensuring that it returns the correct value when the
* thread queried doesn't exist.
*/
+ @Test
public void testGetThreadGroupLeaderInvalidTid() {
// This function takes a TID instead of a PID but BAD_PID should also be a bad TID.
assertEquals(-1, Process.getThreadGroupLeader(BAD_PID));
}
+ @Test
public void testGetAdvertisedMem() {
assertTrue(Process.getAdvertisedMem() > 0);
assertTrue(Process.getTotalMemory() <= Process.getAdvertisedMem());
diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
index eff4826040f4..25ce240d1fb3 100644
--- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
+++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
@@ -24,6 +24,8 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import android.content.Context;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.system.Os;
import androidx.test.InstrumentationRegistry;
@@ -31,6 +33,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,7 +44,11 @@ import java.io.FileOutputStream;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = RedactingFileDescriptor.class)
public class RedactingFileDescriptorTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private Context mContext;
private File mFile;
diff --git a/core/tests/coretests/src/android/os/TraceTest.java b/core/tests/coretests/src/android/os/TraceTest.java
index d07187c2c9d8..593833ec96a7 100644
--- a/core/tests/coretests/src/android/os/TraceTest.java
+++ b/core/tests/coretests/src/android/os/TraceTest.java
@@ -16,24 +16,36 @@
package android.os;
-import android.test.AndroidTestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.Log;
import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* This class is used to test the native tracing support. Run this test
* while tracing on the emulator and then run traceview to view the trace.
*/
-public class TraceTest extends AndroidTestCase
-{
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = Trace.class)
+public class TraceTest {
private static final String TAG = "TraceTest";
+
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private int eMethodCalls = 0;
private int fMethodCalls = 0;
private int gMethodCalls = 0;
+ @Test
public void testNullStrings() {
Trace.traceCounter(Trace.TRACE_TAG_ACTIVITY_MANAGER, null, 42);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, null);
@@ -48,6 +60,7 @@ public class TraceTest extends AndroidTestCase
Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, null, null);
}
+ @Test
@SmallTest
public void testNativeTracingFromJava()
{
@@ -80,7 +93,8 @@ public class TraceTest extends AndroidTestCase
native void nativeMethod();
native void nativeMethodAndStartTracing();
-
+
+ @Test
@LargeTest
@Suppress // Failing.
public void testMethodTracing()
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index ae6e79a040f7..f34b8fd358d9 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -16,12 +16,27 @@
package android.os;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = VintfObject.class)
+public class VintfObjectTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
-public class VintfObjectTest extends TestCase {
/**
* Quick check for {@link VintfObject#report VintfObject.report()}.
*/
+ @Test
public void testReport() {
String[] xmls = VintfObject.report();
assertTrue(xmls.length > 0);
diff --git a/core/tests/coretests/src/android/os/WorkSourceParcelTest.java b/core/tests/coretests/src/android/os/WorkSourceParcelTest.java
index 483160687723..5f49186df0f5 100644
--- a/core/tests/coretests/src/android/os/WorkSourceParcelTest.java
+++ b/core/tests/coretests/src/android/os/WorkSourceParcelTest.java
@@ -16,17 +16,25 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import static org.junit.Assert.assertEquals;
-
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@IgnoreUnderRavenwood(reason = "JNI")
public class WorkSourceParcelTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
/**
* END_OF_PARCEL_MARKER is added at the end of Parcel on native or java side on write and
* then read on java or native side on read. This way we can ensure that no extra data
@@ -41,8 +49,11 @@ public class WorkSourceParcelTest {
String[] names, int parcelEndMarker);
static {
- System.loadLibrary("worksourceparceltest_jni");
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ System.loadLibrary("worksourceparceltest_jni");
+ }
}
+
/**
* Confirm that we can pass WorkSource from native to Java.
*/
diff --git a/core/tests/coretests/src/android/os/WorkSourceTest.java b/core/tests/coretests/src/android/os/WorkSourceTest.java
index 4206fd239528..85dc1277f14f 100644
--- a/core/tests/coretests/src/android/os/WorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/WorkSourceTest.java
@@ -16,9 +16,19 @@
package android.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
import android.os.WorkSource.WorkChain;
-import junit.framework.TestCase;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
@@ -28,7 +38,9 @@ import java.util.List;
*
* These tests will be moved to CTS when finalized.
*/
-public class WorkSourceTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class WorkSourceTest {
+ @Test
public void testWorkChain_add() {
WorkChain wc1 = new WorkChain();
wc1.addNode(56, null);
@@ -46,6 +58,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(2, wc1.getSize());
}
+ @Test
public void testWorkChain_equalsHashCode() {
WorkChain wc1 = new WorkChain();
WorkChain wc2 = new WorkChain();
@@ -78,6 +91,7 @@ public class WorkSourceTest extends TestCase {
assertFalse(wc1.hashCode() == wc2.hashCode());
}
+ @Test
public void testWorkChain_constructor() {
WorkChain wc1 = new WorkChain();
wc1.addNode(1, "foo")
@@ -91,6 +105,7 @@ public class WorkSourceTest extends TestCase {
assertFalse(wc1.equals(wc2));
}
+ @Test
public void testDiff_workChains() {
WorkSource ws1 = new WorkSource();
ws1.add(50);
@@ -104,6 +119,7 @@ public class WorkSourceTest extends TestCase {
assertFalse(ws2.diff(ws1));
}
+ @Test
public void testEquals_workChains() {
WorkSource ws1 = new WorkSource();
ws1.add(50);
@@ -128,6 +144,7 @@ public class WorkSourceTest extends TestCase {
assertFalse(ws3.equals(ws1));
}
+ @Test
public void testEquals_workChains_nullEmptyAreEquivalent() {
// Construct a WorkSource that has no WorkChains, but whose workChains list
// is non-null.
@@ -145,6 +162,7 @@ public class WorkSourceTest extends TestCase {
assertFalse(ws1.equals(ws2));
}
+ @Test
public void testWorkSourceParcelling() {
WorkSource ws = new WorkSource();
@@ -164,6 +182,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(unparcelled, ws);
}
+ @Test
public void testSet_workChains() {
WorkSource ws1 = new WorkSource();
ws1.add(50);
@@ -193,6 +212,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(1, ws1.getWorkChains().get(0).getSize());
}
+ @Test
public void testSet_nullWorkChain() {
WorkSource ws = new WorkSource();
ws.add(60);
@@ -203,6 +223,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(0, ws.getWorkChains().size());
}
+ @Test
public void testAdd_workChains() {
WorkSource ws = new WorkSource();
ws.createWorkChain().addNode(70, "foo");
@@ -224,6 +245,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(2, workChains.size());
}
+ @Test
public void testSet_noWorkChains() {
WorkSource ws = new WorkSource();
ws.set(10);
@@ -237,6 +259,7 @@ public class WorkSourceTest extends TestCase {
assertEquals("foo", ws2.getPackageName(0));
}
+ @Test
public void testDiffChains_noChanges() {
// WorkSources with no chains.
assertEquals(null, WorkSource.diffChains(new WorkSource(), new WorkSource()));
@@ -254,6 +277,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(null, WorkSource.diffChains(ws2, ws1));
}
+ @Test
public void testDiffChains_noChains() {
// Diffs against a worksource with no chains.
WorkSource ws1 = new WorkSource();
@@ -276,6 +300,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(ws2.getWorkChains(), diffs[1]);
}
+ @Test
public void testDiffChains_onlyAdditionsOrRemovals() {
WorkSource ws1 = new WorkSource();
WorkSource ws2 = new WorkSource();
@@ -302,6 +327,7 @@ public class WorkSourceTest extends TestCase {
}
+ @Test
public void testDiffChains_generalCase() {
WorkSource ws1 = new WorkSource();
WorkSource ws2 = new WorkSource();
@@ -340,6 +366,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(new WorkChain().addNode(2, "tag2"), diffs[1].get(1));
}
+ @Test
public void testGetAttributionId() {
WorkSource ws = new WorkSource();
WorkChain wc1 = ws.createWorkChain();
@@ -355,6 +382,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(100, ws.getAttributionUid());
}
+ @Test
public void testGetAttributionIdWithoutWorkChain() {
WorkSource ws1 = new WorkSource(100);
ws1.add(200);
@@ -365,6 +393,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(100, ws2.getAttributionUid());
}
+ @Test
public void testGetAttributionWhenEmpty() {
WorkSource ws = new WorkSource();
assertEquals(-1, ws.getAttributionUid());
@@ -374,6 +403,7 @@ public class WorkSourceTest extends TestCase {
assertNull(wc.getAttributionTag());
}
+ @Test
public void testGetAttributionTag() {
WorkSource ws1 = new WorkSource();
WorkChain wc = ws1.createWorkChain();
@@ -383,6 +413,7 @@ public class WorkSourceTest extends TestCase {
assertEquals("tag", wc.getAttributionTag());
}
+ @Test
public void testRemove_fromChainedWorkSource() {
WorkSource ws1 = new WorkSource();
ws1.createWorkChain().addNode(50, "foo");
@@ -403,6 +434,7 @@ public class WorkSourceTest extends TestCase {
assertEquals(75, ws1.getWorkChains().get(0).getAttributionUid());
}
+ @Test
public void testRemove_fromSameWorkSource() {
WorkSource ws1 = new WorkSource(50, "foo");
WorkSource ws2 = ws1;
@@ -414,6 +446,7 @@ public class WorkSourceTest extends TestCase {
assertEquals("foo", ws1.getPackageName(0));
}
+ @Test
public void testTransferWorkChains() {
WorkSource ws1 = new WorkSource();
WorkChain wc1 = ws1.createWorkChain().addNode(100, "tag");
diff --git a/core/tests/coretests/src/android/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
index 612562eb22dc..e94273e1ada7 100644
--- a/core/tests/coretests/src/android/service/notification/ConditionTest.java
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -21,9 +21,12 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.app.Flags;
import android.net.Uri;
import android.os.Parcel;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -36,6 +39,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -194,4 +198,59 @@ public class ConditionTest {
Condition fromParcel = new Condition(parcel);
assertThat(fromParcel).isEqualTo(cond);
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_unspecifiedSource_succeeds() {
+ new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE);
+ // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_validSource_succeeds() {
+ new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE, Condition.SOURCE_CONTEXT);
+ // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_invalidSource_throws() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new Condition(Uri.parse("uri"), "Summary", Condition.STATE_TRUE, 1000));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_parcelWithInvalidSource_throws() {
+ Condition original = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
+ Condition.SOURCE_SCHEDULE);
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+
+ // Tweak the parcel to contain and invalid source value.
+ parcel.setDataPosition(parcel.dataPosition() - 8); // going back two int fields.
+ parcel.writeInt(100);
+ parcel.setDataPosition(0);
+
+ assertThrows(IllegalArgumentException.class, () -> new Condition(parcel));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_invalidSource_throws() throws Exception {
+ Condition condition = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
+ Condition.SOURCE_SCHEDULE);
+
+ Field typeField = Condition.class.getDeclaredField("source");
+
+ // Reflection on reflection (ugh) to make a final field non-final
+ Field fieldAccessFlagsField = Field.class.getDeclaredField("accessFlags");
+ fieldAccessFlagsField.setAccessible(true);
+ fieldAccessFlagsField.setInt(typeField, typeField.getModifiers() & ~Modifier.FINAL);
+
+ typeField.setInt(condition, 30);
+
+ assertThrows(IllegalArgumentException.class, condition::validate);
+ }
}
diff --git a/core/tests/coretests/src/android/util/SparseSetArrayTest.java b/core/tests/coretests/src/android/util/SparseSetArrayTest.java
index 1df1090e0343..1c72185ea93c 100644
--- a/core/tests/coretests/src/android/util/SparseSetArrayTest.java
+++ b/core/tests/coretests/src/android/util/SparseSetArrayTest.java
@@ -37,6 +37,7 @@ public class SparseSetArrayTest {
public final RavenwoodRule mRavenwood = new RavenwoodRule();
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testAddAll() {
final SparseSetArray<Integer> sparseSetArray = new SparseSetArray<>();
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 6374e5df3307..60a436e6b2c2 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -42,8 +42,8 @@ import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.KeyguardManager;
-import android.app.UiAutomation;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -52,7 +52,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.platform.test.annotations.RequiresFlagsDisabled;
@@ -66,9 +65,9 @@ import android.support.test.uiautomator.Until;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.Flags;
import android.view.accessibility.IAccessibilityManager;
+import android.widget.Button;
import androidx.lifecycle.Lifecycle;
import androidx.test.core.app.ActivityScenario;
@@ -108,7 +107,6 @@ public class AccessibilityShortcutChooserActivityTest {
private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(TEST_PACKAGE,
"class");
private static final long UI_TIMEOUT_MS = 1000;
- private UiAutomation mUiAutomation;
private UiDevice mDevice;
private ActivityScenario<TestAccessibilityShortcutChooserActivity> mScenario;
private TestAccessibilityShortcutChooserActivity mActivity;
@@ -142,7 +140,6 @@ public class AccessibilityShortcutChooserActivityTest {
assumeFalse("AccessibilityShortcutChooserActivity not supported on watch",
pm.hasSystemFeature(PackageManager.FEATURE_WATCH));
- mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mDevice.wakeUp();
when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
@@ -170,6 +167,12 @@ public class AccessibilityShortcutChooserActivityTest {
if (mScenario != null) {
mScenario.close();
}
+ if (mActivity != null) {
+ Dialog permissionDialog = mActivity.getPermissionDialog();
+ if (permissionDialog != null && permissionDialog.isShowing()) {
+ permissionDialog.dismiss();
+ }
+ }
}
@Test
@@ -193,10 +196,8 @@ public class AccessibilityShortcutChooserActivityTest {
openShortcutsList();
mDevice.findObject(By.text(TEST_LABEL)).clickAndWait(Until.newWindow(), UI_TIMEOUT_MS);
- clickSystemDialogButton(ALLOW_LABEL);
+ clickPermissionDialogButton(R.id.accessibility_permission_enable_allow_button);
- assertThat(mDevice.wait(Until.hasObject(By.textStartsWith(LIST_TITLE_LABEL)),
- UI_TIMEOUT_MS)).isTrue();
assertThat(mDevice.wait(Until.hasObject(By.checked(true)), UI_TIMEOUT_MS)).isTrue();
}
@@ -207,10 +208,8 @@ public class AccessibilityShortcutChooserActivityTest {
openShortcutsList();
mDevice.findObject(By.text(TEST_LABEL)).clickAndWait(Until.newWindow(), UI_TIMEOUT_MS);
- clickSystemDialogButton(DENY_LABEL);
+ clickPermissionDialogButton(R.id.accessibility_permission_enable_deny_button);
- assertThat(mDevice.wait(Until.hasObject(By.textStartsWith(LIST_TITLE_LABEL)),
- UI_TIMEOUT_MS)).isTrue();
assertThat(mDevice.wait(Until.hasObject(By.checked(true)), UI_TIMEOUT_MS)).isFalse();
}
@@ -221,11 +220,9 @@ public class AccessibilityShortcutChooserActivityTest {
openShortcutsList();
mDevice.findObject(By.text(TEST_LABEL)).clickAndWait(Until.newWindow(), UI_TIMEOUT_MS);
- clickSystemDialogButton(UNINSTALL_LABEL);
+ clickPermissionDialogButton(R.id.accessibility_permission_enable_uninstall_button);
verify(mPackageInstaller).uninstall(eq(TEST_PACKAGE), any());
- assertThat(mDevice.wait(Until.hasObject(By.textStartsWith(LIST_TITLE_LABEL)),
- UI_TIMEOUT_MS)).isTrue();
assertThat(mDevice.wait(Until.hasObject(By.textStartsWith(TEST_LABEL)),
UI_TIMEOUT_MS)).isFalse();
}
@@ -353,16 +350,13 @@ public class AccessibilityShortcutChooserActivityTest {
mDevice.wait(Until.hasObject(By.textStartsWith(LIST_TITLE_LABEL)), UI_TIMEOUT_MS);
}
- private void clickSystemDialogButton(String dialogButtonText) {
- // Use UiAutomation to find the button because UiDevice struggles to find
- // a UI element in a system dialog.
- final AccessibilityNodeInfo button =
- mUiAutomation.getRootInActiveWindow()
- .findAccessibilityNodeInfosByText(dialogButtonText).stream()
- .filter(AccessibilityNodeInfo::isClickable).findFirst().get();
- final Rect bounds = new Rect();
- button.getBoundsInScreen(bounds);
- mDevice.click(bounds.centerX(), bounds.centerY());
+ private void clickPermissionDialogButton(int buttonId) {
+ Button button = mActivity.getPermissionDialog().findViewById(buttonId);
+ mActivity.runOnUiThread(button::performClick);
+ // Wait for the dialog to go away by waiting for the shortcut chooser
+ // to become visible again.
+ assertThat(mDevice.wait(Until.hasObject(By.textStartsWith(LIST_TITLE_LABEL)),
+ UI_TIMEOUT_MS)).isTrue();
}
/**
@@ -402,6 +396,10 @@ public class AccessibilityShortcutChooserActivityTest {
public Object getSystemService(String name) {
if (Context.ACCESSIBILITY_SERVICE.equals(name)
&& sAccessibilityManagerService != null) {
+ // Warning: This new AccessibilityManager complicates UI inspection
+ // because it breaks the expected "singleton per process" quality of
+ // AccessibilityManager. Debug here if observing unexpected issues
+ // with UI inspection or interaction.
return new AccessibilityManager(this, new Handler(getMainLooper()),
sAccessibilityManagerService, /* userId= */ 0, /* serviceConnect= */ true);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index 8207c9ee5ff3..b70f29038b31 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -29,7 +29,9 @@ import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.SystemClock;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -39,6 +41,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.BinderInternal.CallSession;
import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,13 +59,22 @@ import java.util.Set;
@SmallTest
@RunWith(AndroidJUnit4.class)
@Presubmit
+@IgnoreUnderRavenwood(blockedBy = BinderCallsStats.class)
public class BinderCallsStatsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private static final int WORKSOURCE_UID = Process.FIRST_APPLICATION_UID;
private static final int CALLING_UID = 2;
private static final int REQUEST_SIZE = 2;
private static final int REPLY_SIZE = 3;
private final CachedDeviceState mDeviceState = new CachedDeviceState(false, true);
- private final TestHandler mHandler = new TestHandler();
+ private TestHandler mHandler;
+
+ @Before
+ public void setUp() {
+ mHandler = new TestHandler();
+ }
@Test
public void testDetailedOff() {
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderHeavyHitterTest.java b/core/tests/coretests/src/com/android/internal/os/BinderHeavyHitterTest.java
index e4597b53b1a3..a1b80d24c48f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderHeavyHitterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderHeavyHitterTest.java
@@ -16,11 +16,19 @@
package com.android.internal.os;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
import android.os.Binder;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.os.BinderCallHeavyHitterWatcher.HeavyHitterContainer;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
@@ -29,7 +37,8 @@ import java.util.Random;
/**
* Tests for {@link BinderCallHeavyHitterWatcher}.
*/
-public final class BinderHeavyHitterTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public final class BinderHeavyHitterTest {
private boolean mListenerNotified = false;
@@ -114,6 +123,7 @@ public final class BinderHeavyHitterTest extends TestCase {
}
}
+ @Test
public void testPositive() throws Exception {
BinderCallHeavyHitterWatcher watcher = BinderCallHeavyHitterWatcher.getInstance();
try {
@@ -142,6 +152,7 @@ public final class BinderHeavyHitterTest extends TestCase {
}
}
+ @Test
public void testNegative() throws Exception {
BinderCallHeavyHitterWatcher watcher = BinderCallHeavyHitterWatcher.getInstance();
try {
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
index 7bd53b9d4fcc..31b55e69cf20 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
@@ -23,7 +23,9 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import android.os.Binder;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ArrayMap;
import android.util.proto.ProtoOutputStream;
@@ -36,6 +38,7 @@ import com.android.internal.os.BinderLatencyProto.ApiStats;
import com.android.internal.os.BinderLatencyProto.Dims;
import com.android.internal.os.BinderLatencyProto.RepeatedApiStats;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,7 +50,11 @@ import java.util.Random;
@SmallTest
@RunWith(AndroidJUnit4.class)
@Presubmit
+@IgnoreUnderRavenwood(blockedBy = BinderLatencyObserver.class)
public class BinderLatencyObserverTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void testLatencyCollectionWithMultipleClasses() {
TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderfsStatsReaderTest.java b/core/tests/coretests/src/com/android/internal/os/BinderfsStatsReaderTest.java
index e9f6450c13aa..5f02f046a647 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderfsStatsReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderfsStatsReaderTest.java
@@ -20,11 +20,9 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import android.content.Context;
import android.os.FileUtils;
import android.util.IntArray;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -102,9 +100,8 @@ public class BinderfsStatsReaderTest {
private boolean mHasError;
@Before
- public void setUp() {
- Context context = InstrumentationRegistry.getContext();
- mStatsDirectory = context.getDir("binder_logs", Context.MODE_PRIVATE);
+ public void setUp() throws Exception {
+ mStatsDirectory = Files.createTempDirectory("BinderfsStatsReaderTest").toFile();
mFreezerBinderAsyncThreshold = 1024;
mValidPids = IntArray.fromArray(new int[]{14505, 14461, 542, 540}, 4);
mStatsPids = new IntArray();
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuScalingPolicyReaderTest.java b/core/tests/coretests/src/com/android/internal/os/CpuScalingPolicyReaderTest.java
index 7f054d136639..2da3873341bb 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuScalingPolicyReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuScalingPolicyReaderTest.java
@@ -16,11 +16,8 @@
package com.android.internal.os;
-import static androidx.test.InstrumentationRegistry.getContext;
-
import static com.google.common.truth.Truth.assertThat;
-import android.content.Context;
import android.os.FileUtils;
import androidx.test.runner.AndroidJUnit4;
@@ -31,6 +28,7 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
@RunWith(AndroidJUnit4.class)
public class CpuScalingPolicyReaderTest {
@@ -38,7 +36,7 @@ public class CpuScalingPolicyReaderTest {
@Before
public void setup() throws IOException {
- File testDir = getContext().getDir("test", Context.MODE_PRIVATE);
+ File testDir = Files.createTempDirectory("CpuScalingPolicyReaderTest").toFile();
FileUtils.deleteContents(testDir);
File policy0 = new File(testDir, "policy0");
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
index 2a8a8571c882..4371f2699d4f 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -16,14 +16,22 @@
package com.android.internal.os;
+import static org.junit.Assert.assertTrue;
+
import android.os.Debug;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
-import junit.framework.TestCase;
+import org.junit.Rule;
+import org.junit.Test;
@SmallTest
-public class DebugTest extends TestCase {
+@IgnoreUnderRavenwood(reason = "Requires ART support")
+public class DebugTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private final static String EXPECTED_GET_CALLER =
"com\\.android\\.internal\\.os\\.DebugTest\\.testGetCaller:\\d\\d";
@@ -39,6 +47,7 @@ public class DebugTest extends TestCase {
return Debug.getCaller();
}
+ @Test
public void testGetCaller() {
assertTrue(callDepth0().matches(EXPECTED_GET_CALLER));
}
@@ -62,6 +71,7 @@ public class DebugTest extends TestCase {
return callDepth2();
}
+ @Test
public void testGetCallers() {
assertTrue(callDepth1().matches(EXPECTED_GET_CALLERS));
}
@@ -69,6 +79,7 @@ public class DebugTest extends TestCase {
/**
* Regression test for b/31943543. Note: must be run under CheckJNI to detect the issue.
*/
+ @Test
public void testGetMemoryInfo() {
Debug.MemoryInfo info = new Debug.MemoryInfo();
Debug.getMemoryInfo(-1, info);
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
index cbd2ba4eeabc..1d8628d2ee55 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
@@ -24,6 +24,8 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.os.FileUtils;
import android.os.SystemClock;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -31,6 +33,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,7 +60,11 @@ import java.util.stream.IntStream;
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuProcStringReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private File mRoot;
private File mTestDir;
private File mTestFile;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java
index b45f8d2733db..a57a40046a84 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java
@@ -24,13 +24,16 @@ import static org.testng.Assert.assertThrows;
import static java.util.stream.Collectors.toList;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -44,7 +47,10 @@ import java.util.Collections;
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuThreadReaderDiffTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private MockitoSession mMockingSessions;
@Mock KernelCpuThreadReader mMockReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
index d43989c06a72..8c5e3d0e0724 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertTrue;
import android.os.Process;
import android.os.SystemClock;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
@@ -29,6 +31,7 @@ import androidx.test.filters.LargeTest;
import com.android.internal.os.KernelCpuThreadReader.ProcessCpuUsage;
import com.android.internal.os.KernelCpuThreadReader.ThreadCpuUsage;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,7 +50,10 @@ import java.util.stream.Collectors;
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuThreadReaderEndToEndTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private static final int TIMED_NUM_SAMPLES = 5;
private static final int TIMED_START_MILLIS = 500;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index c3e4014bf29a..7eac2a31bee0 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -25,7 +25,9 @@ import static org.testng.Assert.assertThrows;
import android.content.Context;
import android.os.FileUtils;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -33,6 +35,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,7 +51,11 @@ import java.util.function.Predicate;
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuThreadReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private File mProcDirectory;
@Before
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
index 2ccd74e99116..d35e0fc95aa1 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
@@ -21,6 +21,8 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.os.FileUtils;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseArray;
import android.util.SparseLongArray;
@@ -31,6 +33,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeRead
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -51,7 +54,11 @@ import java.util.Random;
*/
@SmallTest
@RunWith(Parameterized.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuUidActiveTimeReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private File mTestDir;
private File mTestFile;
private KernelCpuUidActiveTimeReader mReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java
index bda21c61375e..610e6aeb210d 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java
@@ -23,11 +23,15 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
import org.junit.runner.RunWith;
import com.android.internal.os.KernelCpuUidBpfMapReader.BpfMapIterator;
@@ -50,7 +54,11 @@ import java.util.stream.IntStream;
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuUidBpfMapReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private Random mRand = new Random(12345);
private KernelCpuUidTestBpfMapReader mReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
index a0dab28a6da5..8807de089864 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.os.FileUtils;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -32,6 +34,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeRea
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -52,7 +55,11 @@ import java.util.Random;
*/
@SmallTest
@RunWith(Parameterized.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuUidClusterTimeReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private File mTestDir;
private File mTestFile;
private KernelCpuUidClusterTimeReader mReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
index 783f264d6772..b73034437350 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
@@ -24,6 +24,8 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.FileUtils;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -33,6 +35,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -55,7 +58,11 @@ import java.util.Random;
*/
@SmallTest
@RunWith(Parameterized.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuUidFreqTimeReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private File mTestDir;
private File mTestFile;
private KernelCpuUidFreqTimeReader mReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
index 1da1a9095d87..65072262c30f 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.os.FileUtils;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -33,6 +35,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeRea
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,7 +52,11 @@ import java.util.Random;
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelCpuUidUserSysTimeReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private File mTestDir;
private File mTestFile;
private KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader mReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
index 60dac8520d14..ad5186e8e3c7 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
@@ -16,12 +16,18 @@
package com.android.internal.os;
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.LongSparseLongArray;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
-
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.io.BufferedReader;
@@ -29,12 +35,17 @@ import java.io.BufferedReader;
/**
* Tests for KernelMemoryBandwidthStats parsing and delta calculation, based on memory_state_time.
*/
-public class KernelMemoryBandwidthStatsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
+public class KernelMemoryBandwidthStatsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
/**
* Standard example of parsing stats.
* @throws Exception
*/
+ @Test
@SmallTest
public void testParseStandard() throws Exception {
KernelMemoryBandwidthStats stats = new KernelMemoryBandwidthStats();
@@ -68,6 +79,7 @@ public class KernelMemoryBandwidthStatsTest extends TestCase {
* zero.
* @throws Exception
*/
+ @Test
@SmallTest
public void testParseBackwards() throws Exception {
KernelMemoryBandwidthStats zeroStats = new KernelMemoryBandwidthStats();
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
index 2de800bb6d00..f42d26de9847 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
@@ -19,9 +19,13 @@ package com.android.internal.os;
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,7 +35,10 @@ import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelSingleProcessCpuThreadReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
@Test
public void getProcessCpuUsage() throws IOException {
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
index 74ab644f1376..120a4de54427 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
@@ -30,6 +32,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.os.KernelSingleUidTimeReader.Injector;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -43,7 +46,11 @@ import java.util.Collection;
@SmallTest
@RunWith(Parameterized.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class KernelSingleUidTimeReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private final static int TEST_UID = 2222;
private final static int TEST_FREQ_COUNT = 5;
diff --git a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
index cb8a62c0936c..632dce0fdc8b 100644
--- a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
@@ -16,9 +16,13 @@
package com.android.internal.os;
-import androidx.test.filters.Suppress;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
-import junit.framework.TestCase;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -28,11 +32,12 @@ import java.util.Collections;
import java.util.List;
// this test causes a IllegalAccessError: superclass not accessible
-@Suppress
-public class LoggingPrintStreamTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class LoggingPrintStreamTest {
TestPrintStream out = new TestPrintStream();
+ @Test
public void testPrintException() {
@SuppressWarnings("ThrowableInstanceNeverThrown")
Throwable t = new Throwable("Ignore me.");
@@ -47,6 +52,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList(lines), out.lines);
}
+ @Test
public void testPrintObject() {
Object o = new Object();
out.print(4);
@@ -56,6 +62,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList("4" + o + "2"), out.lines);
}
+ @Test
public void testPrintlnObject() {
Object o = new Object();
out.print(4);
@@ -65,6 +72,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList("4" + o, "2"), out.lines);
}
+ @Test
public void testPrintf() {
out.printf("Name: %s\nEmployer: %s", "Bob", "Google");
assertEquals(Arrays.asList("Name: Bob"), out.lines);
@@ -72,6 +80,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList("Name: Bob", "Employer: Google"), out.lines);
}
+ @Test
public void testPrintInt() {
out.print(4);
out.print(2);
@@ -80,12 +89,14 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Collections.singletonList("42"), out.lines);
}
+ @Test
public void testPrintlnInt() {
out.println(4);
out.println(2);
assertEquals(Arrays.asList("4", "2"), out.lines);
}
+ @Test
public void testPrintCharArray() {
out.print("Foo\nBar\nTee".toCharArray());
assertEquals(Arrays.asList("Foo", "Bar"), out.lines);
@@ -93,6 +104,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
}
+ @Test
public void testPrintString() {
out.print("Foo\nBar\nTee");
assertEquals(Arrays.asList("Foo", "Bar"), out.lines);
@@ -100,22 +112,26 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
}
+ @Test
public void testPrintlnCharArray() {
out.println("Foo\nBar\nTee".toCharArray());
assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
}
+ @Test
public void testPrintlnString() {
out.println("Foo\nBar\nTee");
assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
}
+ @Test
public void testPrintlnStringWithBufferedData() {
out.print(5);
out.println("Foo\nBar\nTee");
assertEquals(Arrays.asList("5Foo", "Bar", "Tee"), out.lines);
}
+ @Test
public void testAppend() {
out.append("Foo\n")
.append('4')
@@ -125,6 +141,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList("Foo", "4", "a"), out.lines);
}
+ @Test
public void testMultiByteCharactersSpanningBuffers() throws Exception {
// assume 3*1000 bytes won't fit in LoggingPrintStream's internal buffer
StringBuilder builder = new StringBuilder();
@@ -138,6 +155,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList(expected), out.lines);
}
+ @Test
public void testWriteOneByteAtATimeMultibyteCharacters() throws Exception {
String expected = " \u20AC \u20AC \u20AC \u20AC ";
for (byte b : expected.getBytes()) {
@@ -147,6 +165,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList(expected), out.lines);
}
+ @Test
public void testWriteByteArrayAtATimeMultibyteCharacters() throws Exception {
String expected = " \u20AC \u20AC \u20AC \u20AC ";
out.write(expected.getBytes());
@@ -154,6 +173,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList(expected), out.lines);
}
+ @Test
public void testWriteWithOffsetsMultibyteCharacters() throws Exception {
String expected = " \u20AC \u20AC \u20AC \u20AC ";
byte[] bytes = expected.getBytes();
@@ -167,6 +187,7 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList(expected), out.lines);
}
+ @Test
public void testWriteFlushesOnNewlines() throws Exception {
String a = " \u20AC \u20AC ";
String b = " \u20AC \u20AC ";
diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
index faccf1ad19a1..c9536b9b8129 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -22,16 +22,22 @@ import static org.junit.Assert.assertThrows;
import android.os.BadParcelableException;
import android.os.Parcel;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@IgnoreUnderRavenwood(blockedBy = LongArrayMultiStateCounter.class)
public class LongArrayMultiStateCounterTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
@Test
public void setStateAndUpdateValue() {
@@ -51,6 +57,16 @@ public class LongArrayMultiStateCounterTest {
}
@Test
+ public void setValue() {
+ LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
+
+ counter.setValues(0, new long[]{1, 2, 3, 4});
+ counter.setValues(1, new long[]{5, 6, 7, 8});
+ assertCounts(counter, 0, new long[]{1, 2, 3, 4});
+ assertCounts(counter, 1, new long[]{5, 6, 7, 8});
+ }
+
+ @Test
public void setEnabled() {
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
counter.setState(0, 1000);
diff --git a/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
index 341375357902..e064e7483bfa 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
@@ -22,16 +22,22 @@ import static org.junit.Assert.assertThrows;
import android.os.BadParcelableException;
import android.os.Parcel;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@IgnoreUnderRavenwood(blockedBy = LongMultiStateCounterTest.class)
public class LongMultiStateCounterTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
@Test
public void setStateAndUpdateValue() {
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 48baf09f5e10..dfb5cc35c5bc 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -23,6 +23,7 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,6 +31,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,6 +42,9 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
@Presubmit
public final class LooperStatsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private HandlerThread mThreadFirst;
private HandlerThread mThreadSecond;
private Handler mHandlerFirst;
diff --git a/core/tests/coretests/src/com/android/internal/os/MonotonicClockTest.java b/core/tests/coretests/src/com/android/internal/os/MonotonicClockTest.java
index 7951270461d7..0742052cce53 100644
--- a/core/tests/coretests/src/com/android/internal/os/MonotonicClockTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MonotonicClockTest.java
@@ -43,14 +43,12 @@ public class MonotonicClockTest {
assertThat(monotonicClock.monotonicTime()).isEqualTo(1234);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- monotonicClock.writeXml(out, Xml.newFastSerializer());
- String xml = out.toString();
- assertThat(xml).contains("timeshift=\"1234\"");
+ monotonicClock.writeXml(out, Xml.newBinarySerializer());
mClock.realtime = 42;
MonotonicClock newMonotonicClock = new MonotonicClock(0, mClock);
- newMonotonicClock.readXml(new ByteArrayInputStream(out.toByteArray()),
- Xml.newFastPullParser());
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ newMonotonicClock.readXml(in, Xml.newBinaryPullParser());
mClock.realtime = 2000;
assertThat(newMonotonicClock.monotonicTime()).isEqualTo(1234 - 42 + 2000);
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
index 77202d1faa31..c0f0714e52cc 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
@@ -27,6 +27,8 @@ import android.annotation.XmlRes;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -38,6 +40,7 @@ import com.android.internal.util.XmlUtils;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,7 +53,10 @@ import org.junit.runner.RunWith;
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = PowerProfile.class)
public class PowerProfileTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
static final String TAG_TEST_MODEM = "test-modem";
static final String ATTR_NAME = "name";
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
index 29da2319adc2..b99e2026ef26 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
@@ -21,17 +21,23 @@ import static com.google.common.truth.Truth.assertThat;
import android.os.BatteryConsumer;
import android.os.Parcel;
import android.os.PersistableBundle;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class PowerStatsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private PowerStats.DescriptorRegistry mRegistry;
private PowerStats.Descriptor mDescriptor;
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
index c3d40eb09237..f61fc7c33eb3 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
@@ -18,11 +18,9 @@ package com.android.internal.os;
import static org.junit.Assert.assertTrue;
-import android.content.Context;
import android.os.FileUtils;
import android.util.IntArray;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -45,9 +43,8 @@ public class ProcLocksReaderTest implements
private ArrayList<int[]> mPids = new ArrayList<>();
@Before
- public void setUp() {
- Context context = InstrumentationRegistry.getContext();
- mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ public void setUp() throws Exception {
+ mProcDirectory = Files.createTempDirectory("ProcLocksReaderTest").toFile();
}
@After
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
index e97caf8c0631..3e4f34d71f5f 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
@@ -18,10 +18,8 @@ package com.android.internal.os;
import static org.junit.Assert.assertEquals;
-import android.content.Context;
import android.os.FileUtils;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -41,9 +39,8 @@ public class ProcStatsUtilTest {
private File mProcDirectory;
@Before
- public void setUp() {
- Context context = InstrumentationRegistry.getContext();
- mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ public void setUp() throws Exception {
+ mProcDirectory = Files.createTempDirectory("ProcStatsUtilTest").toFile();
}
@After
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
index 9db3f8a6e187..a706350c71a5 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
@@ -20,15 +20,16 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
-import android.content.Context;
import android.os.FileUtils;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,14 +40,16 @@ import java.nio.file.Path;
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ProcTimeInStateReader.class)
public class ProcTimeInStateReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private File mProcDirectory;
@Before
- public void setUp() {
- Context context = InstrumentationRegistry.getContext();
- mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ public void setUp() throws Exception {
+ mProcDirectory = Files.createTempDirectory("ProcTimeInStateReaderTest").toFile();
}
@After
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcessCpuTrackerTest.java b/core/tests/coretests/src/com/android/internal/os/ProcessCpuTrackerTest.java
index 81cc9d830228..d11c500b055a 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcessCpuTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcessCpuTrackerTest.java
@@ -18,15 +18,23 @@ package com.android.internal.os;
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@SmallTest
@RunWith(JUnit4.class)
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class ProcessCpuTrackerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void testGetCpuTime() throws Exception {
final ProcessCpuTracker tracker = new ProcessCpuTracker(false);
diff --git a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
index 85eafc57acc3..84c93c232d9f 100644
--- a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
@@ -20,10 +20,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
-import android.content.Context;
import android.os.FileUtils;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -48,7 +46,6 @@ import java.nio.file.Files;
@RunWith(AndroidJUnit4.class)
public class StoragedUidIoStatsReaderTest {
- private File mRoot;
private File mTestDir;
private File mTestFile;
// private Random mRand = new Random();
@@ -57,15 +54,10 @@ public class StoragedUidIoStatsReaderTest {
@Mock
private StoragedUidIoStatsReader.Callback mCallback;
- private Context getContext() {
- return InstrumentationRegistry.getContext();
- }
-
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mTestDir = getContext().getDir("test", Context.MODE_PRIVATE);
- mRoot = getContext().getFilesDir();
+ mTestDir = Files.createTempDirectory("StoragedUidIoStatsReaderTest").toFile();
mTestFile = new File(mTestDir, "test.file");
mStoragedUidIoStatsReader = new StoragedUidIoStatsReader(mTestFile.getAbsolutePath());
}
@@ -73,10 +65,8 @@ public class StoragedUidIoStatsReaderTest {
@After
public void tearDown() throws Exception {
FileUtils.deleteContents(mTestDir);
- FileUtils.deleteContents(mRoot);
}
-
/**
* Tests that reading will never call the callback.
*/
diff --git a/core/tests/coretests/src/com/android/internal/power/EnergyConsumerStatsTest.java b/core/tests/coretests/src/com/android/internal/power/EnergyConsumerStatsTest.java
index e09cfd21e605..ae2ef0cb4e51 100644
--- a/core/tests/coretests/src/com/android/internal/power/EnergyConsumerStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/EnergyConsumerStatsTest.java
@@ -34,10 +34,13 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.view.Display;
import androidx.test.filters.SmallTest;
+import org.junit.Rule;
import org.junit.Test;
import java.util.Arrays;
@@ -46,7 +49,10 @@ import java.util.Arrays;
* Test class for {@link EnergyConsumerStats}.
*/
@SmallTest
+@IgnoreUnderRavenwood(reason = "Needs kernel support")
public class EnergyConsumerStatsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
@Test
public void testConstruction() {
diff --git a/core/tests/utiltests/src/android/util/TimeUtilsTest.java b/core/tests/utiltests/src/android/util/TimeUtilsTest.java
index e8246c83e086..ac659e1bc593 100644
--- a/core/tests/utiltests/src/android/util/TimeUtilsTest.java
+++ b/core/tests/utiltests/src/android/util/TimeUtilsTest.java
@@ -18,8 +18,12 @@ package android.util;
import static org.junit.Assert.assertEquals;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,6 +33,9 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class TimeUtilsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
public static final long SECOND_IN_MILLIS = 1000;
public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
@@ -78,6 +85,7 @@ public class TimeUtilsTest {
}
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testDumpTime() {
assertEquals("2023-01-01 00:00:00.000", runWithPrintWriter((pw) -> {
TimeUtils.dumpTime(pw, 1672556400000L);
@@ -91,6 +99,7 @@ public class TimeUtilsTest {
}
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testFormatForLogging() {
assertEquals("unknown", TimeUtils.formatForLogging(0));
assertEquals("unknown", TimeUtils.formatForLogging(-1));
@@ -99,6 +108,7 @@ public class TimeUtilsTest {
}
@Test
+ @IgnoreUnderRavenwood(reason = "Flaky test, b/315872700")
public void testLogTimeOfDay() {
assertEquals("01-01 00:00:00.000", TimeUtils.logTimeOfDay(1672556400000L));
}
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index 0c5e9664bbde..fc233fba082e 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -161,6 +161,18 @@ public class ArrayUtilsTest {
}
@Test
+ public void testAppendBoolean() throws Exception {
+ assertArrayEquals(new boolean[] { true },
+ ArrayUtils.appendBoolean(null, true));
+ assertArrayEquals(new boolean[] { true },
+ ArrayUtils.appendBoolean(new boolean[] { }, true));
+ assertArrayEquals(new boolean[] { true, false },
+ ArrayUtils.appendBoolean(new boolean[] { true }, false));
+ assertArrayEquals(new boolean[] { true, true },
+ ArrayUtils.appendBoolean(new boolean[] { true }, true));
+ }
+
+ @Test
public void testRemoveLong() throws Exception {
assertNull(ArrayUtils.removeLong(null, 1));
assertArrayEquals(new long[] { },
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index 15d14e87fcf6..b315f94b5d00 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -241,7 +241,7 @@ public class WindowAreaComponentImpl implements WindowAreaComponent,
for (int i = 0; i < displays.length; i++) {
DisplayAddress.Physical address =
(DisplayAddress.Physical) displays[i].getAddress();
- if (mRearDisplayAddress == address.getPhysicalDisplayId()) {
+ if (address != null && mRearDisplayAddress == address.getPhysicalDisplayId()) {
rearDisplayMetrics = new DisplayMetrics();
final Display rearDisplay = displays[i];
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index f0ed6ee5cb67..e346b51a4f19 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,4 @@
xutan@google.com
# Give submodule owners in shell resource approval
-per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index b1b196d40357..fe65fdd30e48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -16,6 +16,7 @@
package com.android.wm.shell;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -168,6 +169,13 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
private final Object mLock = new Object();
private StartingWindowController mStartingWindow;
+ /** Overlay surface for home root task */
+ private final SurfaceControl mHomeTaskOverlayContainer = new SurfaceControl.Builder()
+ .setName("home_task_overlay_container")
+ .setContainerLayer()
+ .setHidden(false)
+ .build();
+
/**
* In charge of showing compat UI. Can be {@code null} if the device doesn't support size
* compat or if this isn't the main {@link ShellTaskOrganizer}.
@@ -428,6 +436,14 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
}
+ /**
+ * Returns a surface which can be used to attach overlays to the home root task
+ */
+ @NonNull
+ public SurfaceControl getHomeTaskOverlayContainer() {
+ return mHomeTaskOverlayContainer;
+ }
+
@Override
public void addStartingWindow(StartingWindowInfo info) {
if (mStartingWindow != null) {
@@ -485,6 +501,15 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
if (mUnfoldAnimationController != null) {
mUnfoldAnimationController.onTaskAppeared(info.getTaskInfo(), info.getLeash());
}
+
+ if (info.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
+ ProtoLog.v(WM_SHELL_TASK_ORG, "Adding overlay to home task");
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setLayer(mHomeTaskOverlayContainer, Integer.MAX_VALUE);
+ t.reparent(mHomeTaskOverlayContainer, info.getLeash());
+ t.apply();
+ }
+
notifyLocusVisibilityIfNeeded(info.getTaskInfo());
notifyCompatUI(info.getTaskInfo(), listener);
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo()));
@@ -579,6 +604,12 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
notifyCompatUI(taskInfo, null /* taskListener */);
// Notify the recent tasks that a task has been removed
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
+ if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.reparent(mHomeTaskOverlayContainer, null);
+ t.apply();
+ ProtoLog.v(WM_SHELL_TASK_ORG, "Removing overlay surface");
+ }
if (!ENABLE_SHELL_TRANSITIONS && (appearedInfo.getLeash() != null)) {
// Preemptively clean up the leash only if shell transitions are not enabled
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index c98090638010..8d8dc10951a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -49,6 +49,11 @@ public interface BackAnimation {
@BackEvent.SwipeEdge int swipeEdge);
/**
+ * Called when the input pointers are pilfered.
+ */
+ void onPilferPointers();
+
+ /**
* Sets whether the back gesture is past the trigger threshold or not.
*/
void setTriggerBack(boolean triggerBack);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index cf858dcb0637..d8c691b01b61 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -111,6 +111,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
/** Tracks if we should start the back gesture on the next motion move event */
private boolean mShouldStartOnNextMoveEvent = false;
+ private boolean mOnBackStartDispatched = false;
private final FlingAnimationUtils mFlingAnimationUtils;
@@ -304,6 +305,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
@Override
+ public void onPilferPointers() {
+ BackAnimationController.this.onPilferPointers();
+ }
+
+ @Override
public void setTriggerBack(boolean triggerBack) {
mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack));
}
@@ -384,6 +390,16 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return null;
}
+ @VisibleForTesting
+ void onPilferPointers() {
+ mCurrentTracker.updateStartLocation();
+ // Dispatch onBackStarted, only to app callbacks.
+ // System callbacks will receive onBackStarted when the remote animation starts.
+ if (!shouldDispatchToAnimator()) {
+ tryDispatchOnBackStarted(mActiveCallback, mCurrentTracker.createStartEvent(null));
+ }
+ }
+
/**
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
@@ -483,12 +499,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
// App is handling back animation. Cancel system animation latency tracking.
cancelLatencyTracking();
- dispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
+ tryDispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
}
}
private void onMove() {
- if (!mBackGestureStarted || mBackNavigationInfo == null || mActiveCallback == null) {
+ if (!mBackGestureStarted
+ || mBackNavigationInfo == null
+ || mActiveCallback == null
+ || !mOnBackStartDispatched) {
return;
}
// Skip dispatching if the move corresponds to the queued instead of the current gesture
@@ -524,13 +543,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
&& mBackNavigationInfo.isPrepareRemoteAnimation();
}
- private void dispatchOnBackStarted(IOnBackInvokedCallback callback,
+ private void tryDispatchOnBackStarted(IOnBackInvokedCallback callback,
BackMotionEvent backEvent) {
- if (callback == null) {
+ if (callback == null || mOnBackStartDispatched) {
return;
}
try {
callback.onBackStarted(backEvent);
+ mOnBackStartDispatched = true;
} catch (RemoteException e) {
Log.e(TAG, "dispatchOnBackStarted error: ", e);
}
@@ -828,6 +848,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
void finishBackNavigation(boolean triggerBack) {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()");
mActiveCallback = null;
+ mShouldStartOnNextMoveEvent = false;
+ mOnBackStartDispatched = false;
mShellBackAnimationRegistry.resetDefaultCrossActivity();
cancelLatencyTracking();
if (mBackNavigationInfo != null) {
@@ -909,7 +931,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
::onBackAnimationFinished));
if (apps.length >= 1) {
- dispatchOnBackStarted(
+ mCurrentTracker.updateStartLocation();
+ tryDispatchOnBackStarted(
mActiveCallback,
mCurrentTracker.createStartEvent(apps[0]));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 19eb928d4e30..4bd56d460818 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -104,6 +104,15 @@ class TouchTracker {
mStartThresholdX = mInitTouchX;
}
+ /** Update the start location used to compute the progress
+ * to the latest touch location.
+ */
+ void updateStartLocation() {
+ mInitTouchX = mLatestTouchX;
+ mInitTouchY = mLatestTouchY;
+ mStartThresholdX = mInitTouchX;
+ }
+
void reset() {
mInitTouchX = 0;
mInitTouchY = 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 689323b725ae..7f34ee0cdd3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -78,34 +78,37 @@ public class BubbleBarAnimationHelper {
mExpandedViewAlphaAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- if (mExpandedBubble != null && mExpandedBubble.getBubbleBarExpandedView() != null) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev != null) {
// We need to be Z ordered on top in order for alpha animations to work.
- mExpandedBubble.getBubbleBarExpandedView().setSurfaceZOrderedOnTop(true);
- mExpandedBubble.getBubbleBarExpandedView().setAnimating(true);
+ bbev.setSurfaceZOrderedOnTop(true);
+ bbev.setAnimating(true);
}
}
@Override
public void onAnimationEnd(Animator animation) {
- if (mExpandedBubble != null && mExpandedBubble.getBubbleBarExpandedView() != null) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev != null) {
// The surface needs to be Z ordered on top for alpha values to work on the
// TaskView, and if we're temporarily hidden, we are still on the screen
// with alpha = 0f until we animate back. Stay Z ordered on top so the alpha
// = 0f remains in effect.
if (mIsExpanded) {
- mExpandedBubble.getBubbleBarExpandedView().setSurfaceZOrderedOnTop(false);
+ bbev.setSurfaceZOrderedOnTop(false);
}
- mExpandedBubble.getBubbleBarExpandedView().setContentVisibility(mIsExpanded);
- mExpandedBubble.getBubbleBarExpandedView().setAnimating(false);
+ bbev.setContentVisibility(mIsExpanded);
+ bbev.setAnimating(false);
}
}
});
mExpandedViewAlphaAnimator.addUpdateListener(valueAnimator -> {
- if (mExpandedBubble != null && mExpandedBubble.getBubbleBarExpandedView() != null) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev != null) {
float alpha = (float) valueAnimator.getAnimatedValue();
- mExpandedBubble.getBubbleBarExpandedView().setTaskViewAlpha(alpha);
- mExpandedBubble.getBubbleBarExpandedView().setAlpha(alpha);
+ bbev.setTaskViewAlpha(alpha);
+ bbev.setAlpha(alpha);
}
});
}
@@ -116,11 +119,8 @@ public class BubbleBarAnimationHelper {
public void animateExpansion(BubbleViewProvider expandedBubble,
@Nullable Runnable afterAnimation) {
mExpandedBubble = expandedBubble;
- if (mExpandedBubble == null) {
- return;
- }
- BubbleBarExpandedView bev = mExpandedBubble.getBubbleBarExpandedView();
- if (bev == null) {
+ final BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
return;
}
mIsExpanded = true;
@@ -129,11 +129,11 @@ public class BubbleBarAnimationHelper {
mExpandedViewContainerMatrix.setScaleY(0f);
updateExpandedView();
- bev.setAnimating(true);
- bev.setContentVisibility(false);
- bev.setAlpha(0f);
- bev.setTaskViewAlpha(0f);
- bev.setVisibility(VISIBLE);
+ bbev.setAnimating(true);
+ bbev.setContentVisibility(false);
+ bbev.setAlpha(0f);
+ bbev.setTaskViewAlpha(0f);
+ bbev.setVisibility(VISIBLE);
// Set the pivot point for the scale, so the view animates out from the bubble bar.
Point bubbleBarPosition = mPositioner.getBubbleBarPosition();
@@ -143,7 +143,7 @@ public class BubbleBarAnimationHelper {
bubbleBarPosition.x,
bubbleBarPosition.y);
- bev.setAnimationMatrix(mExpandedViewContainerMatrix);
+ bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
mExpandedViewAlphaAnimator.start();
@@ -156,13 +156,12 @@ public class BubbleBarAnimationHelper {
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
mScaleInSpringConfig)
.addUpdateListener((target, values) -> {
- mExpandedBubble.getBubbleBarExpandedView().setAnimationMatrix(
- mExpandedViewContainerMatrix);
+ bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
})
.withEndActions(() -> {
- bev.setAnimationMatrix(null);
+ bbev.setAnimationMatrix(null);
updateExpandedView();
- bev.setSurfaceZOrderedOnTop(false);
+ bbev.setSurfaceZOrderedOnTop(false);
if (afterAnimation != null) {
afterAnimation.run();
}
@@ -177,7 +176,8 @@ public class BubbleBarAnimationHelper {
*/
public void animateCollapse(Runnable endRunnable) {
mIsExpanded = false;
- if (mExpandedBubble == null || mExpandedBubble.getBubbleBarExpandedView() == null) {
+ final BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
Log.w(TAG, "Trying to animate collapse without a bubble");
return;
}
@@ -196,17 +196,10 @@ public class BubbleBarAnimationHelper {
EXPANDED_VIEW_ANIMATE_OUT_SCALE_AMOUNT),
mScaleOutSpringConfig)
.addUpdateListener((target, values) -> {
- if (mExpandedBubble != null
- && mExpandedBubble.getBubbleBarExpandedView() != null) {
- mExpandedBubble.getBubbleBarExpandedView().setAnimationMatrix(
- mExpandedViewContainerMatrix);
- }
+ bbev.setAnimationMatrix(mExpandedViewContainerMatrix);
})
.withEndActions(() -> {
- if (mExpandedBubble != null
- && mExpandedBubble.getBubbleBarExpandedView() != null) {
- mExpandedBubble.getBubbleBarExpandedView().setAnimationMatrix(null);
- }
+ bbev.setAnimationMatrix(null);
if (endRunnable != null) {
endRunnable.run();
}
@@ -223,12 +216,20 @@ public class BubbleBarAnimationHelper {
mExpandedViewAlphaAnimator.cancel();
}
+ private @Nullable BubbleBarExpandedView getExpandedView() {
+ BubbleViewProvider bubble = mExpandedBubble;
+ if (bubble != null) {
+ return bubble.getBubbleBarExpandedView();
+ }
+ return null;
+ }
+
private void updateExpandedView() {
- if (mExpandedBubble == null || mExpandedBubble.getBubbleBarExpandedView() == null) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
Log.w(TAG, "Trying to update the expanded view without a bubble");
return;
}
- BubbleBarExpandedView bbev = mExpandedBubble.getBubbleBarExpandedView();
boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
final int padding = mPositioner.getBubbleBarExpandedViewPadding();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 0f0fbd9cc12f..f801b0d01084 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -83,6 +83,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private int mStartPos;
private GestureDetector mDoubleTapDetector;
private boolean mInteractive;
+ private boolean mHideHandle;
private boolean mSetTouchRegion = true;
private int mLastDraggingPosition;
private int mHandleRegionWidth;
@@ -211,11 +212,8 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
}
/** Sets up essential dependencies of the divider bar. */
- public void setup(
- SplitLayout layout,
- SplitWindowManager splitWindowManager,
- SurfaceControlViewHost viewHost,
- InsetsState insetsState) {
+ public void setup(SplitLayout layout, SplitWindowManager splitWindowManager,
+ SurfaceControlViewHost viewHost, InsetsState insetsState) {
mSplitLayout = layout;
mSplitWindowManager = splitWindowManager;
mViewHost = viewHost;
@@ -277,6 +275,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
R.dimen.docked_stack_divider_lift_elevation);
mDoubleTapDetector = new GestureDetector(getContext(), new DoubleTapListener());
mInteractive = true;
+ mHideHandle = false;
setOnTouchListener(this);
mHandle.setAccessibilityDelegate(mHandleDelegate);
setWillNotDraw(false);
@@ -469,10 +468,11 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
void setInteractive(boolean interactive, boolean hideHandle, String from) {
if (interactive == mInteractive) return;
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
- "Set divider bar %s from %s", interactive ? "interactive" : "non-interactive",
- from);
+ "Set divider bar %s hide handle=%b from %s",
+ interactive ? "interactive" : "non-interactive", hideHandle, from);
mInteractive = interactive;
- if (!mInteractive && hideHandle && mMoving) {
+ mHideHandle = hideHandle;
+ if (!mInteractive && mHideHandle && mMoving) {
final int position = mSplitLayout.getDividePosition();
mSplitLayout.flingDividePosition(
mLastDraggingPosition,
@@ -482,7 +482,15 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mMoving = false;
}
releaseTouching();
- mHandle.setVisibility(!mInteractive && hideHandle ? View.INVISIBLE : View.VISIBLE);
+ mHandle.setVisibility(!mInteractive && mHideHandle ? View.INVISIBLE : View.VISIBLE);
+ }
+
+ boolean isInteractive() {
+ return mInteractive;
+ }
+
+ boolean isHandleHidden() {
+ return mHideHandle;
}
private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index b699533374df..53caddb52f23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -59,6 +59,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
@@ -70,6 +71,7 @@ import com.android.wm.shell.common.InteractionJankMonitorUtils;
import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -420,7 +422,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void init() {
if (mInitialized) return;
mInitialized = true;
- mSplitWindowManager.init(this, mInsetsState);
+ mSplitWindowManager.init(this, mInsetsState, false /* isRestoring */);
mDisplayImeController.addPositionProcessor(mImePositionProcessor);
}
@@ -442,14 +444,19 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
/** Releases and re-inflates {@link DividerView} on the root surface. */
- public void update(SurfaceControl.Transaction t) {
+ public void update(SurfaceControl.Transaction t, boolean resetImePosition) {
if (!mInitialized) {
init();
return;
}
mSplitWindowManager.release(t);
- mImePositionProcessor.reset();
- mSplitWindowManager.init(this, mInsetsState);
+ if (resetImePosition) {
+ mImePositionProcessor.reset();
+ }
+ mSplitWindowManager.init(this, mInsetsState, true /* isRestoring */);
+ // Update the surface positions again after recreating the divider in case nothing else
+ // triggers it
+ mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
}
@Override
@@ -868,6 +875,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
pw.println(prefix + TAG + ":");
pw.println(innerPrefix + "mAllowLeftRightSplitInPortrait=" + mAllowLeftRightSplitInPortrait);
pw.println(innerPrefix + "mIsLeftRightSplit=" + mIsLeftRightSplit);
+ pw.println(innerPrefix + "mFreezeDividerWindow=" + mFreezeDividerWindow);
+ pw.println(innerPrefix + "mDimNonImeSide=" + mDimNonImeSide);
+ pw.println(innerPrefix + "mDividerPosition=" + mDividerPosition);
pw.println(innerPrefix + "bounds1=" + mBounds1.toShortString());
pw.println(innerPrefix + "dividerBounds=" + mDividerBounds.toShortString());
pw.println(innerPrefix + "bounds2=" + mBounds2.toShortString());
@@ -1151,14 +1161,16 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mTargetYOffset = needOffset ? getTargetYOffset() : 0;
if (mTargetYOffset != mLastYOffset) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Split IME animation starting, fromY=%d toY=%d",
+ mLastYOffset, mTargetYOffset);
// Freeze the configuration size with offset to prevent app get a configuration
// changed or relaunch. This is required to make sure client apps will calculate
// insets properly after layout shifted.
if (mTargetYOffset == 0) {
mSplitLayoutHandler.setLayoutOffsetTarget(0, 0, SplitLayout.this);
} else {
- mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset - mLastYOffset,
- SplitLayout.this);
+ mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset, SplitLayout.this);
}
}
@@ -1183,6 +1195,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void onImeEndPositioning(int displayId, boolean cancel,
SurfaceControl.Transaction t) {
if (displayId != mDisplayId || !mHasImeFocus || cancel) return;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Split IME animation ending, canceled=%b", cancel);
onProgress(1.0f);
mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 00361d9dd9cf..8fb9bda539a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -62,6 +62,10 @@ public final class SplitWindowManager extends WindowlessWindowManager {
// Used to "pass" a transaction to WWM.remove so that view removal can be synchronized.
private SurfaceControl.Transaction mSyncTransaction = null;
+ // For saving/restoring state
+ private boolean mLastDividerInteractive = true;
+ private boolean mLastDividerHandleHidden;
+
public interface ParentContainerCallbacks {
void attachToParentSurface(SurfaceControl.Builder b);
void onLeashReady(SurfaceControl leash);
@@ -107,7 +111,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
}
/** Inflates {@link DividerView} on to the root surface. */
- void init(SplitLayout splitLayout, InsetsState insetsState) {
+ void init(SplitLayout splitLayout, InsetsState insetsState, boolean isRestoring) {
if (mDividerView != null || mViewHost != null) {
throw new UnsupportedOperationException(
"Try to inflate divider view again without release first");
@@ -130,6 +134,10 @@ public final class SplitWindowManager extends WindowlessWindowManager {
lp.accessibilityTitle = mContext.getResources().getString(R.string.accessibility_divider);
mViewHost.setView(mDividerView, lp);
mDividerView.setup(splitLayout, this, mViewHost, insetsState);
+ if (isRestoring) {
+ mDividerView.setInteractive(mLastDividerInteractive, mLastDividerHandleHidden,
+ "restore_setup");
+ }
}
/**
@@ -138,6 +146,8 @@ public final class SplitWindowManager extends WindowlessWindowManager {
*/
void release(@Nullable SurfaceControl.Transaction t) {
if (mDividerView != null) {
+ mLastDividerInteractive = mDividerView.isInteractive();
+ mLastDividerHandleHidden = mDividerView.isHandleHidden();
mDividerView = null;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
index ef763ec45994..afd3b14e8b1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Rect;
import android.os.SystemClock;
import android.view.LayoutInflater;
@@ -227,9 +228,12 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
}
private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
+ final Intent intent = taskInfo.baseIntent;
return taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton
&& (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed
|| taskInfo.appCompatTaskInfo.isUserFullscreenOverrideEnabled)
+ && Intent.ACTION_MAIN.equals(intent.getAction())
+ && intent.hasCategory(Intent.CATEGORY_LAUNCHER)
&& (!mUserAspectRatioButtonShownChecker.get() || isShowingButton());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
index deb7c6db338f..1385f42bc676 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
@@ -1,3 +1,7 @@
# WM shell sub-module desktop owners
atsjenk@google.com
+jorgegil@google.com
madym@google.com
+nmusgrave@google.com
+pbdr@google.com
+tkachenkoi@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
index a3803ed82844..8a0eea0a9bdd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
@@ -2,3 +2,6 @@
atsjenk@google.com
jorgegil@google.com
madym@google.com
+nmusgrave@google.com
+pbdr@google.com
+tkachenkoi@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index f5c01d063707..4c477373c32c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -769,7 +769,6 @@ public class PipAnimationController {
getSurfaceTransactionHelper().crop(tx, leash, destBounds);
}
if (mContentOverlay != null) {
- mContentOverlay.onAnimationEnd(tx, destBounds);
clearContentOverlay();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index a2bd47c5285e..e11e8596a7fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -67,15 +67,6 @@ public abstract class PipContentOverlay {
public abstract void onAnimationUpdate(SurfaceControl.Transaction atomicTx,
Rect currentBounds, float fraction);
- /**
- * Callback when reaches the end of animation on the internal {@link #mLeash}.
- * @param atomicTx {@link SurfaceControl.Transaction} to operate, you should not explicitly
- * call apply on this transaction, it should be applied on the caller side.
- * @param destinationBounds {@link Rect} of the final bounds.
- */
- public abstract void onAnimationEnd(SurfaceControl.Transaction atomicTx,
- Rect destinationBounds);
-
/** A {@link PipContentOverlay} uses solid color. */
public static final class PipColorOverlay extends PipContentOverlay {
private static final String TAG = PipColorOverlay.class.getSimpleName();
@@ -107,11 +98,6 @@ public abstract class PipContentOverlay {
atomicTx.setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2);
}
- @Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Color overlay should be fully opaque by now, ready for fade out.
- }
-
private float[] getContentOverlayColor(Context context) {
final TypedArray ta = context.obtainStyledAttributes(new int[] {
android.R.attr.colorBackground });
@@ -164,11 +150,6 @@ public abstract class PipContentOverlay {
Rect currentBounds, float fraction) {
// Do nothing. Keep the snapshot till animation ends.
}
-
- @Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Snapshot overlay should be fully opaque by now, ready for fade out.
- }
}
/** A {@link PipContentOverlay} shows app icon on solid color background. */
@@ -255,11 +236,6 @@ public abstract class PipContentOverlay {
}
@Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Icon overlay should be fully opaque by now, ready for fade out.
- }
-
- @Override
public void detach(SurfaceControl.Transaction tx) {
super.detach(tx);
if (mBitmap != null && !mBitmap.isRecycled()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 743b1ea197bc..3635165d76ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -329,15 +329,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private @Surface.Rotation int mCurrentRotation;
/**
- * An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link PipTransitionState#getInSwipePipToHomeTransition()} is true, only in gesture nav.
- */
- @Nullable
- SurfaceControl mSwipePipToHomeOverlay;
-
- /**
- * An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link PipTransitionState#getInSwipePipToHomeTransition()} is false.
+ * An optional overlay used to mask content changing between an app in/out of PiP.
*/
@Nullable
SurfaceControl mPipOverlay;
@@ -480,7 +472,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
mPipBoundsState.setBounds(destinationBounds);
- mSwipePipToHomeOverlay = overlay;
+ mPipOverlay = overlay;
if (ENABLE_SHELL_TRANSITIONS && overlay != null) {
// With Shell transition, the overlay was attached to the remote transition leash, which
// will be removed when the current transition is finished, so we need to reparent it
@@ -892,7 +884,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
final Rect destinationBounds = mPipBoundsState.getBounds();
- final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay;
+ final SurfaceControl swipeToHomeOverlay = mPipOverlay;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.resetScale(tx, mLeash, destinationBounds)
@@ -911,7 +903,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}, tx);
mPipTransitionState.setInSwipePipToHomeTransition(false);
- mSwipePipToHomeOverlay = null;
+ mPipOverlay = null;
}
private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
@@ -1126,9 +1118,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
clearWaitForFixedRotation();
- if (mSwipePipToHomeOverlay != null) {
- removeContentOverlay(mSwipePipToHomeOverlay, null /* callback */);
- mSwipePipToHomeOverlay = null;
+ if (mPipOverlay != null) {
+ removeContentOverlay(mPipOverlay, null /* callback */);
+ mPipOverlay = null;
}
resetShadowRadius();
mPipTransitionState.setInSwipePipToHomeTransition(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 0f3c16220dee..f5f15d81ea44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -465,7 +465,7 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper.crop(tx, leash, destinationBounds)
.resetScale(tx, leash, destinationBounds)
.round(tx, leash, true /* applyCornerRadius */);
- if (mPipOrganizer.mSwipePipToHomeOverlay != null && !mInitBounds.isEmpty()) {
+ if (mPipOrganizer.mPipOverlay != null && !mInitBounds.isEmpty()) {
// Resetting the scale for pinned task while re-adjusting its crop,
// also scales the overlay. So we need to update the overlay leash too.
Rect overlayBounds = new Rect(destinationBounds);
@@ -476,7 +476,7 @@ public class PipTransition extends PipTransitionController {
(destinationBounds.width() - overlaySize) / 2,
(destinationBounds.height() - overlaySize) / 2);
mSurfaceTransactionHelper.resetScale(tx,
- mPipOrganizer.mSwipePipToHomeOverlay, overlayBounds);
+ mPipOrganizer.mPipOverlay, overlayBounds);
}
}
mInitBounds.setEmpty();
@@ -615,9 +615,9 @@ public class PipTransition extends PipTransitionController {
}
}
// if overlay is present remove it immediately, as exit transition came before it faded out
- if (mPipOrganizer.mSwipePipToHomeOverlay != null) {
- startTransaction.remove(mPipOrganizer.mSwipePipToHomeOverlay);
- clearSwipePipToHomeOverlay();
+ if (mPipOrganizer.mPipOverlay != null) {
+ startTransaction.remove(mPipOrganizer.mPipOverlay);
+ clearPipOverlay();
}
if (pipChange == null) {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -1077,7 +1077,7 @@ public class PipTransition extends PipTransitionController {
if (mFixedRotationState == FIXED_ROTATION_CALLBACK && appBounds != null) {
mInitBounds.set(appBounds);
}
- final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
+ final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mPipOverlay;
if (swipePipToHomeOverlay != null) {
// Launcher fade in the overlay on top of the fullscreen Task. It is possible we
// reparent the PIP activity to a new PIP task (in case there are other activities
@@ -1106,7 +1106,7 @@ public class PipTransition extends PipTransitionController {
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
if (swipePipToHomeOverlay != null) {
mPipOrganizer.fadeOutAndRemoveOverlay(swipePipToHomeOverlay,
- this::clearSwipePipToHomeOverlay /* callback */, false /* withStartDelay */);
+ this::clearPipOverlay /* callback */, false /* withStartDelay */);
}
mPipTransitionState.setInSwipePipToHomeTransition(false);
}
@@ -1250,8 +1250,8 @@ public class PipTransition extends PipTransitionController {
mPipMenuController.updateMenuBounds(destinationBounds);
}
- private void clearSwipePipToHomeOverlay() {
- mPipOrganizer.mSwipePipToHomeOverlay = null;
+ private void clearPipOverlay() {
+ mPipOrganizer.mPipOverlay = null;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 0367ba160605..d023cea6d19d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -995,16 +995,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
t.show(mOpeningTasks.get(i).mTaskSurface);
}
for (int i = 0; i < mPausingTasks.size(); ++i) {
- if (!sendUserLeaveHint && mPausingTasks.get(i).isLeaf()) {
- // This means recents is not *actually* finishing, so of course we gotta
- // do special stuff in WMCore to accommodate.
- wct.setDoNotPip(mPausingTasks.get(i).mToken);
- }
- // Since we will reparent out of the leashes, pre-emptively hide the child
- // surface to match the leash. Otherwise, there will be a flicker before the
- // visibility gets committed in Core when using split-screen (in splitscreen,
- // the leaf-tasks are not "independent" so aren't hidden by normal setup).
- t.hide(mPausingTasks.get(i).mTaskSurface);
+ cleanUpPausingOrClosingTask(mPausingTasks.get(i), wct, t, sendUserLeaveHint);
+ }
+ for (int i = 0; i < mClosingTasks.size(); ++i) {
+ cleanUpPausingOrClosingTask(mClosingTasks.get(i), wct, t, sendUserLeaveHint);
}
if (mPipTransaction != null && sendUserLeaveHint) {
SurfaceControl pipLeash = null;
@@ -1053,6 +1047,20 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
}
+ private void cleanUpPausingOrClosingTask(TaskState task, WindowContainerTransaction wct,
+ SurfaceControl.Transaction finishTransaction, boolean sendUserLeaveHint) {
+ if (!sendUserLeaveHint && task.isLeaf()) {
+ // This means recents is not *actually* finishing, so of course we gotta
+ // do special stuff in WMCore to accommodate.
+ wct.setDoNotPip(task.mToken);
+ }
+ // Since we will reparent out of the leashes, pre-emptively hide the child
+ // surface to match the leash. Otherwise, there will be a flicker before the
+ // visibility gets committed in Core when using split-screen (in splitscreen,
+ // the leaf-tasks are not "independent" so aren't hidden by normal setup).
+ finishTransaction.hide(task.mTaskSurface);
+ }
+
@Override
public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 449bef5608c9..96e57e71f05c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -223,6 +223,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private boolean mExitSplitScreenOnHide;
private boolean mIsDividerRemoteAnimating;
private boolean mIsDropEntering;
+ private boolean mSkipEvictingMainStageChildren;
private boolean mIsExiting;
private boolean mIsRootTranslucent;
@VisibleForTesting
@@ -468,6 +469,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
// Due to drag already pip task entering split by this method so need to reset flag here.
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
return true;
}
@@ -572,6 +574,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
+ // Don't evict the main stage children as this can race and happen after the activity is
+ // started into that stage
+ if (!isSplitScreenVisible()) {
+ mSkipEvictingMainStageChildren = true;
+ // Starting the split task without evicting children will bring the single root task
+ // container forward, so ensure that we hide the divider before we start animate it
+ setDividerVisibility(false, null);
+ }
+
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -600,6 +611,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
+ // Don't evict the main stage children as this can race and happen after the activity is
+ // started into that stage
+ if (!isSplitScreenVisible()) {
+ mSkipEvictingMainStageChildren = true;
+ // Starting the split task without evicting children will bring the single root task
+ // container forward, so ensure that we hide the divider before we start animate it
+ setDividerVisibility(false, null);
+ }
+
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -1618,7 +1638,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Ensure to evict old splitting tasks because the new split pair might be composed by
// one of the splitting tasks, evicting the task when finishing entering transition
// won't guarantee to put the task to the indicated new position.
- if (!mIsDropEntering) {
+ if (!mSkipEvictingMainStageChildren) {
mMainStage.evictAllChildren(wct);
}
mMainStage.reparentTopTask(wct);
@@ -1666,7 +1686,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
- mSplitLayout.update(finishT);
+ mSplitLayout.update(finishT, true /* resetImePosition */);
mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash,
getMainStageBounds());
mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash,
@@ -1680,6 +1700,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
finishT.show(mRootTaskLeash);
setSplitsVisible(true);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
mSplitRequest = null;
updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) {
@@ -1860,9 +1881,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
&& mMainStage.isActive()) {
// Clear the divider remote animating flag as the divider will be re-rendered to apply
- // the new rotation config.
+ // the new rotation config. Don't reset the IME state since those updates are not in
+ // sync with task info changes.
mIsDividerRemoteAnimating = false;
- mSplitLayout.update(null /* t */);
+ mSplitLayout.update(null /* t */, false /* resetImePosition */);
onLayoutSizeChanged(mSplitLayout);
}
}
@@ -1928,6 +1950,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mIsDropEntering) {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
mSplitLayout.flingDividerToCenter();
@@ -2122,6 +2145,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mIsDropEntering) {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
mSplitLayout.flingDividerToCenter();
@@ -2325,7 +2349,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
*/
public void updateSurfaces(SurfaceControl.Transaction transaction) {
updateSurfaceBounds(mSplitLayout, transaction, /* applyResizingOffset */ false);
- mSplitLayout.update(transaction);
+ mSplitLayout.update(transaction, true /* resetImePosition */);
}
private void onDisplayChange(int displayId, int fromRotation, int toRotation,
@@ -2598,7 +2622,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
&& (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
- mSplitLayout.update(startTransaction);
+ // Don't reset the IME state since those updates are not in sync with the
+ // display change transition
+ mSplitLayout.update(startTransaction, false /* resetImePosition */);
}
if (mMixedHandler.isEnteringPip(change, transitType)) {
@@ -2699,7 +2725,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
startTransaction, finishTransaction, finishCallback)) {
if (mSplitTransitions.isPendingResize(transition)) {
// Only need to update in resize because divider exist before transition.
- mSplitLayout.update(startTransaction);
+ mSplitLayout.update(startTransaction, true /* resetImePosition */);
startTransaction.apply();
}
return true;
@@ -3242,6 +3268,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
if (!isSplitScreenVisible()) {
mIsDropEntering = true;
+ mSkipEvictingMainStageChildren = true;
}
if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
// If split running background, exit split first.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index e03f82526bdb..34c015f05c68 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -330,6 +330,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
continue;
}
if (isHide) {
+ if (pending.mType == TRANSIT_TO_BACK) {
+ // TO_BACK is only used when setting the task view visibility immediately,
+ // so in that case we can also hide the surface immediately
+ startTransaction.hide(chg.getLeash());
+ }
tv.prepareHideAnimation(finishTransaction);
} else {
tv.prepareCloseAnimation();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
index 644a6a5114a7..7f4a8f1d476a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
@@ -16,6 +16,7 @@
package com.android.wm.shell.transition;
+import android.view.SurfaceControl;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
@@ -42,6 +43,13 @@ interface IShellTransitions {
*/
IBinder getShellApplyToken() = 3;
- /** Set listener that will receive callbacks about transitions involving home activity */
+ /**
+ * Set listener that will receive callbacks about transitions involving home activity.
+ */
oneway void setHomeTransitionListener(in IHomeTransitionListener listener) = 4;
+
+ /**
+ * Returns a container surface for the home root task.
+ */
+ SurfaceControl getHomeTaskOverlayContainer() = 5;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index b98762d5e104..af69b5272ad5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -64,7 +64,6 @@ import android.window.TransitionInfo;
import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
import androidx.annotation.BinderThread;
@@ -72,6 +71,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
@@ -172,7 +172,7 @@ public class Transitions implements RemoteCallable<Transitions>,
/** Transition to animate task to desktop. */
public static final int TRANSIT_MOVE_TO_DESKTOP = WindowManager.TRANSIT_FIRST_CUSTOM + 15;
- private final WindowOrganizer mOrganizer;
+ private final ShellTaskOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
private final ShellExecutor mAnimExecutor;
@@ -264,7 +264,7 @@ public class Transitions implements RemoteCallable<Transitions>,
public Transitions(@NonNull Context context,
@NonNull ShellInit shellInit,
@NonNull ShellController shellController,
- @NonNull WindowOrganizer organizer,
+ @NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
@NonNull ShellExecutor mainExecutor,
@@ -280,7 +280,7 @@ public class Transitions implements RemoteCallable<Transitions>,
@NonNull ShellInit shellInit,
@Nullable ShellCommandHandler shellCommandHandler,
@NonNull ShellController shellController,
- @NonNull WindowOrganizer organizer,
+ @NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
@NonNull ShellExecutor mainExecutor,
@@ -1240,6 +1240,10 @@ public class Transitions implements RemoteCallable<Transitions>,
}
}
+ private SurfaceControl getHomeTaskOverlayContainer() {
+ return mOrganizer.getHomeTaskOverlayContainer();
+ }
+
/**
* Interface for a callback that must be called after a TransitionHandler finishes playing an
* animation.
@@ -1470,6 +1474,17 @@ public class Transitions implements RemoteCallable<Transitions>,
listener);
});
}
+
+ @Override
+ public SurfaceControl getHomeTaskOverlayContainer() {
+ SurfaceControl[] result = new SurfaceControl[1];
+ executeRemoteCallWithTaskPermission(mTransitions, "getHomeTaskOverlayContainer",
+ (controller) -> {
+ result[0] = controller.getHomeTaskOverlayContainer();
+ }, true /* blocking */);
+ // Return a copy as writing to parcel releases the original surface
+ return new SurfaceControl(result[0], "Transitions.HomeOverlay");
+ }
}
private class SettingsObserver extends ContentObserver {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 20ff79f7318e..98d343b66760 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.unfold;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
@@ -245,23 +246,29 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
public boolean shouldPlayUnfoldAnimation(@NonNull TransitionInfo transitionInfo) {
// Unfold animation won't play when animations are disabled
if (!ValueAnimator.areAnimatorsEnabled()) return false;
+ // Only handle transitions that are marked as physical display switch
+ // See PhysicalDisplaySwitchTransitionLauncher for the conditions
+ if ((transitionInfo.getFlags() & TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH) == 0) return false;
for (int i = 0; i < transitionInfo.getChanges().size(); i++) {
final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
- if ((change.getFlags() & TransitionInfo.FLAG_IS_DISPLAY) != 0) {
- if (change.getEndAbsBounds() == null || change.getStartAbsBounds() == null) {
- continue;
- }
+ // We are interested only in display container changes
+ if ((change.getFlags() & TransitionInfo.FLAG_IS_DISPLAY) == 0) {
+ continue;
+ }
- // Handle only unfolding, currently we don't have an animation when folding
- final int afterArea =
- change.getEndAbsBounds().width() * change.getEndAbsBounds().height();
- final int beforeArea = change.getStartAbsBounds().width()
- * change.getStartAbsBounds().height();
+ // Handle only unfolding, currently we don't have an animation when folding
+ if (change.getEndAbsBounds() == null || change.getStartAbsBounds() == null) {
+ continue;
+ }
- if (afterArea > beforeArea) {
- return true;
- }
+ final int afterArea =
+ change.getEndAbsBounds().width() * change.getEndAbsBounds().height();
+ final int beforeArea = change.getStartAbsBounds().width()
+ * change.getStartAbsBounds().height();
+
+ if (afterArea > beforeArea) {
+ return true;
}
}
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index deebad545c5e..d718e157afdb 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -9,3 +9,6 @@ hwwang@google.com
chenghsiuchang@google.com
atsjenk@google.com
jorgegil@google.com
+nmusgrave@google.com
+pbdr@google.com
+tkachenkoi@google.com
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 0395a9b78b2b..771876f7ce5d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -182,8 +182,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
}
private void triggerBackGesture() {
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 0);
+ doStartEvents(0, 0);
mController.setTriggerBack(true);
}
@@ -244,10 +243,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
- // Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -270,10 +266,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ true);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
// Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100, 3000);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -359,8 +353,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
.injectInputEvent(any(KeyEvent.class), any(Integer.class));
// Verify that we start accepting gestures again once transition finishes.
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -399,8 +392,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
.injectInputEvent(any(KeyEvent.class), any(Integer.class));
// Verify that we start accepting gestures again once transition finishes.
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -427,8 +419,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
mShellExecutor.flushAll();
reset(mAnimatorCallback);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
}
@@ -441,9 +432,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- // Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -563,10 +552,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
// Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -593,6 +580,15 @@ public class BackAnimationControllerTest extends ShellTestCase {
/* swipeEdge */ BackEvent.EDGE_LEFT);
}
+ /**
+ * Simulate event sequence that starts a back navigation.
+ */
+ private void doStartEvents(int startX, int moveX) {
+ doMotionEvent(MotionEvent.ACTION_DOWN, startX);
+ mController.onPilferPointers();
+ doMotionEvent(MotionEvent.ACTION_MOVE, moveX);
+ }
+
private void simulateRemoteAnimationStart() throws RemoteException {
RemoteAnimationTarget animationTarget = createAnimationTarget();
RemoteAnimationTarget[] targets = new RemoteAnimationTarget[]{animationTarget};
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
index 145c8f0ab8af..636c6326d213 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
@@ -69,7 +69,7 @@ public class DividerViewTest extends ShellTestCase {
SplitWindowManager splitWindowManager = new SplitWindowManager("TestSplitWindowManager",
mContext,
configuration, mCallbacks);
- splitWindowManager.init(mSplitLayout, new InsetsState());
+ splitWindowManager.init(mSplitLayout, new InsetsState(), false /* isRestoring */);
mDividerView = spy((DividerView) splitWindowManager.getDividerView());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 2e5078d86a8b..150aa13f2d00 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -59,7 +59,7 @@ public class SplitWindowManagerTests extends ShellTestCase {
@Test
@UiThreadTest
public void testInitRelease() {
- mSplitWindowManager.init(mSplitLayout, new InsetsState());
+ mSplitWindowManager.init(mSplitLayout, new InsetsState(), false /* isRestoring */);
assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
mSplitWindowManager.release(null /* t */);
assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
index 065293960da7..9fe2cb11e804 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
@@ -16,6 +16,9 @@
package com.android.wm.shell.compatui;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_LAUNCHER;
+import static android.hardware.usb.UsbManager.ACTION_USB_STATE;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -33,6 +36,7 @@ import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
@@ -108,7 +112,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mExecutor = new TestShellExecutor();
mTaskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- false, /* topActivityBoundsLetterboxed */ true);
+ false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
mSyncTransactionQueue, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
mOnUserAspectRatioSettingsButtonClicked, mExecutor, flags -> 0,
@@ -179,7 +183,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
// No diff
clearInvocations(mWindowManager);
TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- true, /* topActivityBoundsLetterboxed */ true);
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
assertTrue(mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true));
verify(mWindowManager, never()).updateSurfacePosition();
@@ -200,7 +204,24 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
clearInvocations(mWindowManager);
clearInvocations(mLayout);
taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- false, /* topActivityBoundsLetterboxed */ true);
+ false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
+ assertFalse(
+ mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
+ verify(mWindowManager).release();
+
+ // Recreate button
+ clearInvocations(mWindowManager);
+ taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
+ assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
+
+ verify(mWindowManager).release();
+ verify(mWindowManager).createLayout(/* canShow= */ true);
+
+ // Change has no launcher category and is not main intent, dispose the component
+ clearInvocations(mWindowManager);
+ taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_USB_STATE, "");
assertFalse(
mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true));
verify(mWindowManager).release();
@@ -217,7 +238,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
// inflated
clearInvocations(mWindowManager);
TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- false, /* topActivityBoundsLetterboxed */ true);
+ false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
verify(mWindowManager, never()).inflateLayout();
@@ -225,7 +246,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
// Change topActivityInSizeCompat to true and pass canShow true, layout should be inflated.
clearInvocations(mWindowManager);
taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- true, /* topActivityBoundsLetterboxed */ true);
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
verify(mWindowManager).inflateLayout();
@@ -304,7 +325,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
clearInvocations(mWindowManager);
spyOn(mWindowManager);
TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
- true, /* topActivityBoundsLetterboxed */ true);
+ true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
// User aspect ratio settings button has not yet been shown.
doReturn(false).when(mUserAspectRatioButtonShownChecker).get();
@@ -378,7 +399,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
}
private static TaskInfo createTaskInfo(boolean eligibleForUserAspectRatioButton,
- boolean topActivityBoundsLetterboxed) {
+ boolean topActivityBoundsLetterboxed, String action, String category) {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.taskId = TASK_ID;
taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton =
@@ -386,6 +407,7 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed = topActivityBoundsLetterboxed;
taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
taskInfo.realActivity = new ComponentName("com.mypackage.test", "TestActivity");
+ taskInfo.baseIntent = new Intent(action).addCategory(category);
return taskInfo;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index 50802c3759c9..66efa02de764 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -40,12 +40,12 @@ import android.os.RemoteException;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionInfo.TransitionMode;
-import android.window.WindowOrganizer;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
@@ -68,7 +68,7 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class HomeTransitionObserverTest extends ShellTestCase {
- private final WindowOrganizer mOrganizer = mock(WindowOrganizer.class);
+ private final ShellTaskOrganizer mOrganizer = mock(ShellTaskOrganizer.class);
private final TransactionPool mTransactionPool = mock(TransactionPool.class);
private final Context mContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 01c9bd0cb9f7..e22bf3de30e4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -87,7 +87,6 @@ import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -98,6 +97,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
@@ -130,7 +130,7 @@ import java.util.function.Function;
@RunWith(AndroidJUnit4.class)
public class ShellTransitionTests extends ShellTestCase {
- private final WindowOrganizer mOrganizer = mock(WindowOrganizer.class);
+ private final ShellTaskOrganizer mOrganizer = mock(ShellTaskOrganizer.class);
private final TransactionPool mTransactionPool = mock(TransactionPool.class);
private final Context mContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index fc1fe1cd0acc..c5e229feaba7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -18,12 +18,11 @@ package com.android.wm.shell.unfold;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static android.view.WindowManager.TRANSIT_NONE;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -40,22 +39,17 @@ import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import com.android.window.flags.FakeFeatureFlagsImpl;
-import com.android.window.flags.FeatureFlags;
-import com.android.window.flags.Flags;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.TransitionInfoBuilder;
+import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback;
import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
import com.android.wm.shell.unfold.animation.SplitTaskUnfoldAnimator;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.List;
@@ -196,6 +190,22 @@ public class UnfoldTransitionHandlerTest {
}
@Test
+ public void startAnimation_differentTransitionFromRequestWithResize_doesNotStartAnimation() {
+ mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo());
+ TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class);
+
+ boolean animationStarted = mUnfoldTransitionHandler.startAnimation(
+ mTransition,
+ createDisplayResizeTransitionInfo(),
+ mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class),
+ finishCallback
+ );
+
+ assertThat(animationStarted).isFalse();
+ }
+
+ @Test
public void startAnimation_differentTransitionFromRequestWithoutUnfold_doesNotStart() {
mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo());
TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class);
@@ -403,24 +413,18 @@ public class UnfoldTransitionHandlerTest {
}
}
- static class TestCase {
- private final boolean mShouldHandleMixedUnfold;
-
- public TestCase(boolean shouldHandleMixedUnfold) {
- mShouldHandleMixedUnfold = shouldHandleMixedUnfold;
- }
-
- public boolean mixedUnfoldFlagEnabled() {
- return mShouldHandleMixedUnfold;
- }
-
- @Override
- public String toString() {
- return "shouldHandleMixedUnfold flag = " + mShouldHandleMixedUnfold;
- }
+ private TransitionInfo createUnfoldTransitionInfo() {
+ TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
+ TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
+ change.setStartAbsBounds(new Rect(0, 0, 10, 10));
+ change.setEndAbsBounds(new Rect(0, 0, 100, 100));
+ change.setFlags(TransitionInfo.FLAG_IS_DISPLAY);
+ transitionInfo.addChange(change);
+ transitionInfo.setFlags(TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH);
+ return transitionInfo;
}
- private TransitionInfo createUnfoldTransitionInfo() {
+ private TransitionInfo createDisplayResizeTransitionInfo() {
TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
change.setStartAbsBounds(new Rect(0, 0, 10, 10));
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 79a735786c38..47411701e5ab 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -79,14 +79,6 @@ cc_defaults {
"external/skia/src/core",
],
- product_variables: {
- eng: {
- lto: {
- never: true,
- },
- },
- },
-
target: {
android: {
include_dirs: [
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 8445032293dd..69718a6c4b3e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -43,12 +43,15 @@ cc_test {
},
shared_libs: [
"libandroid_runtime",
+ "libbase",
+ "libinput",
"libinputservice",
"libhwui",
"libgui",
"libutils",
],
static_libs: [
+ "libflagtest",
"libgmock",
"libgtest",
],
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index d9efd3c2fd83..adfa91e96ebb 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <com_android_input_flags.h>
+#include <flag_macros.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/PointerController.h>
@@ -28,6 +30,8 @@
namespace android {
+namespace input_flags = com::android::input::flags;
+
enum TestCursorType {
CURSOR_TYPE_DEFAULT = 0,
CURSOR_TYPE_HOVER,
@@ -261,7 +265,20 @@ TEST_F(PointerControllerTest, useStylusTypeForStylusHover) {
mPointerController->reloadPointerResources();
}
-TEST_F(PointerControllerTest, updatePointerIcon) {
+TEST_F_WITH_FLAGS(PointerControllerTest, setPresentationBeforeDisplayViewportDoesNotLoadResources,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(input_flags, enable_pointer_choreographer))) {
+ // Setting the presentation mode before a display viewport is set will not load any resources.
+ mPointerController->setPresentation(PointerController::Presentation::POINTER);
+ ASSERT_TRUE(mPolicy->noResourcesAreLoaded());
+
+ // When the display is set, then the resources are loaded.
+ ensureDisplayViewportIsSet();
+ ASSERT_TRUE(mPolicy->allResourcesAreLoaded());
+}
+
+TEST_F_WITH_FLAGS(PointerControllerTest, updatePointerIcon,
+ REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(input_flags,
+ enable_pointer_choreographer))) {
ensureDisplayViewportIsSet();
mPointerController->setPresentation(PointerController::Presentation::POINTER);
mPointerController->unfade(PointerController::Transition::IMMEDIATE);
@@ -277,6 +294,24 @@ TEST_F(PointerControllerTest, updatePointerIcon) {
mPointerController->updatePointerIcon(static_cast<PointerIconStyle>(type));
}
+TEST_F_WITH_FLAGS(PointerControllerTest, updatePointerIconWithChoreographer,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(input_flags, enable_pointer_choreographer))) {
+ // When PointerChoreographer is enabled, the presentation mode is set before the viewport.
+ mPointerController->setPresentation(PointerController::Presentation::POINTER);
+ ensureDisplayViewportIsSet();
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
+
+ int32_t type = CURSOR_TYPE_ADDITIONAL;
+ std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
+ EXPECT_CALL(*mPointerSprite, setVisible(true));
+ EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
+ EXPECT_CALL(*mPointerSprite,
+ setIcon(AllOf(Field(&SpriteIcon::style, static_cast<PointerIconStyle>(type)),
+ Field(&SpriteIcon::hotSpotX, hotspot.first),
+ Field(&SpriteIcon::hotSpotY, hotspot.second))));
+ mPointerController->updatePointerIcon(static_cast<PointerIconStyle>(type));
+}
+
TEST_F(PointerControllerTest, setCustomPointerIcon) {
ensureDisplayViewportIsSet();
mPointerController->unfade(PointerController::Transition::IMMEDIATE);
diff --git a/media/OWNERS b/media/OWNERS
index 4a6648e91af4..994a7b810009 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -21,7 +21,6 @@ wonsik@google.com
include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
# SEO
-sungsoo@google.com
# SEA/KIR/BVE
jtinker@google.com
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index bbe5e06bb282..058c5be6af6c 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -2,7 +2,6 @@
fgoldfain@google.com
elaurent@google.com
lajos@google.com
-sungsoo@google.com
jmtrivi@google.com
# go/android-fwk-media-solutions for info on areas of ownership.
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 901ea46ba38b..a8ffd2b4dd8f 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -110,6 +110,10 @@ interface ITvInputManager {
void pauseRecording(in IBinder sessionToken, in Bundle params, int userId);
void resumeRecording(in IBinder sessionToken, in Bundle params, int userId);
+ // For playback control
+ void startPlayback(in IBinder sessionToken, int userId);
+ void stopPlayback(in IBinder sessionToken, int mode, int userId);
+
// For broadcast info
void requestBroadcastInfo(in IBinder sessionToken, in BroadcastInfoRequest request, int userId);
void removeBroadcastInfo(in IBinder sessionToken, int id, int userId);
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 5246f5c4dc1e..e37ee6e342e5 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -63,6 +63,9 @@ oneway interface ITvInputSession {
void timeShiftSetMode(int mode);
void timeShiftEnablePositionTracking(boolean enable);
+ void startPlayback();
+ void stopPlayback(int mode);
+
// For the recording session
void startRecording(in Uri programUri, in Bundle params);
void stopRecording();
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index d749b91e3889..ae3ee6535c71 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -79,6 +79,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
private static final int DO_TIME_SHIFT_SET_MODE = 30;
private static final int DO_SET_TV_MESSAGE_ENABLED = 31;
private static final int DO_NOTIFY_TV_MESSAGE = 32;
+ private static final int DO_STOP_PLAYBACK = 33;
+ private static final int DO_START_PLAYBACK = 34;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -286,6 +288,14 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mTvInputSessionImpl.onTvMessageReceived((Integer) args.arg1, (Bundle) args.arg2);
break;
}
+ case DO_STOP_PLAYBACK: {
+ mTvInputSessionImpl.stopPlayback(msg.arg1);
+ break;
+ }
+ case DO_START_PLAYBACK: {
+ mTvInputSessionImpl.startPlayback();
+ break;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -483,6 +493,17 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
enabled));
}
+ @Override
+ public void stopPlayback(int mode) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_STOP_PLAYBACK, mode));
+ }
+
+ @Override
+ public void startPlayback() {
+ mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_START_PLAYBACK));
+ }
+
+
private final class TvInputEventReceiver extends InputEventReceiver {
TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 631ab9a2693d..c685a5adb08b 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -339,6 +339,14 @@ public final class TvInputManager {
*/
public static final int VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN = VIDEO_UNAVAILABLE_REASON_END;
+ /**
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * it has been stopped by stopPlayback.
+ * @hide
+ */
+ public static final int VIDEO_UNAVAILABLE_REASON_STOPPED = 19;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
@@ -3302,6 +3310,30 @@ public final class TvInputManager {
}
}
+ void stopPlayback(int mode) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.stopPlayback(mToken, mode, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void startPlayback() {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.startPlayback(mToken, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sends TV messages to the service for testing purposes
*/
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 720d9a6291de..55fa51755177 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -34,6 +34,7 @@ import android.graphics.Rect;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioPresentation;
import android.media.PlaybackParams;
+import android.media.tv.interactive.TvInteractiveAppService;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -1531,6 +1532,32 @@ public abstract class TvInputService extends Service {
}
/**
+ * Called when the application requests playback of the Audio, Video, and CC streams to be
+ * stopped, but the metadata should continue to be filtered.
+ *
+ * <p>The metadata that will continue to be filtered includes the PSI
+ * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1.
+ *
+ * <p> Note that this is different form {@link #timeShiftPause()} as should release the
+ * stream, making it impossible to resume from this position again.
+ * @param mode
+ * @hide
+ */
+ public void onStopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) {
+ }
+
+ /**
+ * Starts playback of the Audio, Video, and CC streams.
+ *
+ * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be
+ * used after stopping playback. This is used to restart playback from the current position
+ * in the live broadcast.
+ * @hide
+ */
+ public void onStartPlayback() {
+ }
+
+ /**
* Called when the application requests to play a given recorded TV program.
*
* @param recordedProgramUri The URI of a recorded TV program.
@@ -1993,6 +2020,20 @@ public abstract class TvInputService extends Service {
}
/**
+ * Calls {@link #onStopPlayback(int)}.
+ */
+ void stopPlayback(int mode) {
+ onStopPlayback(mode);
+ }
+
+ /**
+ * Calls {@link #onStartPlayback()}.
+ */
+ void startPlayback() {
+ onStartPlayback();
+ }
+
+ /**
* Calls {@link #onTimeShiftPlay(Uri)}.
*/
void timeShiftPlay(Uri recordedProgramUri) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 196b5c3112c0..233f96675543 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -37,6 +37,7 @@ import android.media.PlaybackParams;
import android.media.tv.TvInputManager.Session;
import android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
import android.media.tv.TvInputManager.SessionCallback;
+import android.media.tv.interactive.TvInteractiveAppService;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -643,6 +644,35 @@ public class TvView extends ViewGroup {
}
}
+ /**
+ * Stops playback of the Audio, Video, and CC streams, but continue filtering the metadata.
+ *
+ * <p>The metadata that will continue to be filtered includes the PSI
+ * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1.
+ *
+ * <p> Note that this is different form {@link #timeShiftPause()} as this completely drops
+ * the stream, making it impossible to resume from this position again.
+ * @hide
+ */
+ public void stopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) {
+ if (mSession != null) {
+ mSession.stopPlayback(mode);
+ }
+ }
+
+ /**
+ * Starts playback of the Audio, Video, and CC streams.
+ *
+ * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be
+ * used after stopping playback. This is used to restart playback from the current position
+ * in the live broadcast.
+ * @hide
+ */
+ public void startPlayback() {
+ if (mSession != null) {
+ mSession.startPlayback();
+ }
+ }
/**
* Sends TV messages to the session for testing purposes
diff --git a/media/java/android/media/tv/ad/TvAdService.java b/media/java/android/media/tv/ad/TvAdService.java
index 61101f07923c..6897a78647c2 100644
--- a/media/java/android/media/tv/ad/TvAdService.java
+++ b/media/java/android/media/tv/ad/TvAdService.java
@@ -28,6 +28,14 @@ public abstract class TvAdService extends Service {
private static final String TAG = "TvAdService";
/**
+ * Name under which a TvAdService component publishes information about itself. This meta-data
+ * must reference an XML resource containing an
+ * <code>&lt;{@link android.R.styleable#TvAdService tv-ad-service}&gt;</code> tag.
+ * @hide
+ */
+ public static final String SERVICE_META_DATA = "android.media.tv.ad.service";
+
+ /**
* Base class for derived classes to implement to provide a TV AD session.
*/
public abstract static class Session implements KeyEvent.Callback {
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 281eba66123b..6019aa8560e1 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -156,7 +156,7 @@
<string name="permission_storage">Photos and media</string>
<!-- Notification permission will be granted of corresponding profile [CHAR LIMIT=30] -->
- <string name="permission_notification">Notifications</string>
+ <string name="permission_notifications">Notifications</string>
<!-- Apps permission will be granted of corresponding profile [CHAR LIMIT=30] -->
<string name="permission_app_streaming">Apps</string>
@@ -165,28 +165,31 @@
<string name="permission_nearby_device_streaming">Streaming</string>
<!-- Description of phone permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_phone_summary">Can make and manage phone calls</string>
+ <string name="permission_phone_summary">Make and manage phone calls</string>
<!-- Description of Call logs permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_call_logs_summary">Can read and write phone call log</string>
+ <string name="permission_call_logs_summary">Read and write phone call log</string>
<!-- Description of SMS permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_sms_summary">Can send and view SMS messages</string>
+ <string name="permission_sms_summary">Send and view SMS messages</string>
<!-- Description of contacts permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_contacts_summary">Can access your contacts</string>
+ <string name="permission_contacts_summary">Access your contacts</string>
<!-- Description of calendar permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_calendar_summary">Can access your calendar</string>
+ <string name="permission_calendar_summary">Access your calendar</string>
<!-- Description of microphone permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_microphone_summary">Can record audio</string>
+ <string name="permission_microphone_summary">Record audio</string>
<!-- Description of nearby devices' permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_nearby_devices_summary">Can find, connect to, and determine the relative position of nearby devices</string>
+ <string name="permission_nearby_devices_summary">Find, connect to, and determine the relative position of nearby devices</string>
- <!-- Description of notification permission of corresponding profile [CHAR LIMIT=NONE] -->
- <string name="permission_notification_summary">Can read all notifications, including information like contacts, messages, and photos</string>
+ <!-- Description of NLA (notification listener access) of corresponding profile [CHAR LIMIT=NONE] -->
+ <string name="permission_notification_listener_access_summary">Read all notifications, including information like contacts, messages, and photos</string>
+
+ <!-- Description of NLA & POST_NOTIFICATION of corresponding profile [CHAR LIMIT=NONE] -->
+ <string name="permission_notifications_summary">\u2022 Read all notifications, including info like contacts, messages, and photos&lt;br/>\u2022 Send notifications&lt;br/>&lt;br/>You can manage this app\'s ability to read and send notifications anytime in Settings > Notifications.</string>
<!-- Description of app streaming permission of corresponding profile [CHAR LIMIT=NONE] -->
<string name="permission_app_streaming_summary">Stream your phone\u2019s apps</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 97016f5384f6..66282dc209ed 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -27,13 +27,13 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_TYPES;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICON;
-import static com.android.companiondevicemanager.CompanionDeviceResources.SUMMARIES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_PERMISSIONS;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_NAMES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICONS;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_SUMMARIES;
import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES;
import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_SELF_MANAGED_PROFILES;
-import static com.android.companiondevicemanager.CompanionDeviceResources.TITLES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_TITLES;
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
import static com.android.companiondevicemanager.Utils.getIcon;
@@ -482,7 +482,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
return;
}
- title = getHtmlFromResources(this, TITLES.get(deviceProfile), deviceName);
+ title = getHtmlFromResources(this, PROFILE_TITLES.get(deviceProfile), deviceName);
setupPermissionList(deviceProfile);
// Summary is not needed for selfManaged dialog.
@@ -525,7 +525,16 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
- final Drawable profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
+ final Drawable profileIcon = getIcon(this, PROFILE_ICONS.get(deviceProfile));
+
+ // No need to show permission consent dialog if it is a isSkipPrompt(true)
+ // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ Log.d(TAG, "Skipping the permission consent dialog.");
+ mSingleDeviceSpinner.setVisibility(View.GONE);
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
updatePermissionUi();
@@ -545,14 +554,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
- profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
+ profileIcon = getIcon(this, PROFILE_ICONS.get(deviceProfile));
if (deviceProfile == null) {
title = getHtmlFromResources(this, R.string.chooser_title_non_profile, appLabel);
mButtonNotAllowMultipleDevices.setText(R.string.consent_no);
} else {
title = getHtmlFromResources(this,
- R.string.chooser_title, getString(PROFILES_NAME.get(deviceProfile)));
+ R.string.chooser_title, getString(PROFILE_NAMES.get(deviceProfile)));
}
mDeviceAdapter = new DeviceListAdapter(this, this::onDeviceClicked);
@@ -598,6 +607,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
Log.d(TAG, "onDeviceClicked(): " + mSelectedDevice.toShortString());
+ // No need to show permission consent dialog if it is a isSkipPrompt(true)
+ // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ Log.d(TAG, "Skipping the permission consent dialog.");
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
+
updatePermissionUi();
mSummary.setVisibility(View.VISIBLE);
@@ -609,20 +626,12 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private void updatePermissionUi() {
final String deviceProfile = mRequest.getDeviceProfile();
- final int summaryResourceId = SUMMARIES.get(deviceProfile);
+ final int summaryResourceId = PROFILE_SUMMARIES.get(deviceProfile);
final String remoteDeviceName = mSelectedDevice.getDisplayName();
final Spanned title = getHtmlFromResources(
- this, TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
+ this, PROFILE_TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
final Spanned summary;
- // No need to show permission consent dialog if it is a isSkipPrompt(true)
- // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
- if (mRequest.isSkipPrompt()) {
- mSingleDeviceSpinner.setVisibility(View.GONE);
- onUserSelectedDevice(mSelectedDevice);
- return;
- }
-
if (deviceProfile == null && mRequest.isSingleDevice()) {
summary = getHtmlFromResources(this, summaryResourceId, remoteDeviceName);
mConstraintList.setVisibility(View.GONE);
@@ -680,7 +689,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
// and when mPermissionListRecyclerView is fully populated.
// Lastly, disable the Allow and Don't allow buttons.
private void setupPermissionList(String deviceProfile) {
- final List<Integer> permissionTypes = new ArrayList<>(PERMISSION_TYPES.get(deviceProfile));
+ final List<Integer> permissionTypes = new ArrayList<>(
+ PROFILE_PERMISSIONS.get(deviceProfile));
mPermissionListAdapter.setPermissionType(permissionTypes);
mPermissionListRecyclerView.setAdapter(mPermissionListAdapter);
mPermissionListRecyclerView.setLayoutManager(mPermissionsLayoutManager);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
index 551e9754032b..23a11d618085 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
@@ -22,28 +22,15 @@ import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
-
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_APP_STREAMING;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CALENDAR;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CALL_LOGS;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CHANGE_MEDIA_OUTPUT;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CONTACTS;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_MICROPHONE;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NEARBY_DEVICES;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NEARBY_DEVICE_STREAMING;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NOTIFICATION;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_PHONE;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_SMS;
-import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_STORAGE;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;
+import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.media.flags.Flags;
-
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -54,7 +41,85 @@ import java.util.Set;
* for the corresponding profile.
*/
final class CompanionDeviceResources {
- static final Map<String, Integer> TITLES;
+
+ // Permission resources
+ private static final int PERMISSION_NOTIFICATION_LISTENER_ACCESS = 0;
+ private static final int PERMISSION_STORAGE = 1;
+ private static final int PERMISSION_APP_STREAMING = 2;
+ private static final int PERMISSION_PHONE = 3;
+ private static final int PERMISSION_SMS = 4;
+ private static final int PERMISSION_CONTACTS = 5;
+ private static final int PERMISSION_CALENDAR = 6;
+ private static final int PERMISSION_NEARBY_DEVICES = 7;
+ private static final int PERMISSION_NEARBY_DEVICE_STREAMING = 8;
+ private static final int PERMISSION_MICROPHONE = 9;
+ private static final int PERMISSION_CALL_LOGS = 10;
+ // Notification Listener Access & POST_NOTIFICATION permission
+ private static final int PERMISSION_NOTIFICATIONS = 11;
+ private static final int PERMISSION_CHANGE_MEDIA_OUTPUT = 12;
+
+ static final Map<Integer, Integer> PERMISSION_TITLES;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(PERMISSION_NOTIFICATION_LISTENER_ACCESS, R.string.permission_notifications);
+ map.put(PERMISSION_STORAGE, R.string.permission_storage);
+ map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming);
+ map.put(PERMISSION_PHONE, R.string.permission_phone);
+ map.put(PERMISSION_SMS, R.string.permission_sms);
+ map.put(PERMISSION_CONTACTS, R.string.permission_contacts);
+ map.put(PERMISSION_CALENDAR, R.string.permission_calendar);
+ map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming);
+ map.put(PERMISSION_MICROPHONE, R.string.permission_microphone);
+ map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs);
+ map.put(PERMISSION_NOTIFICATIONS, R.string.permission_notifications);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control);
+ PERMISSION_TITLES = unmodifiableMap(map);
+ }
+
+ static final Map<Integer, Integer> PERMISSION_SUMMARIES;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
+ R.string.permission_notification_listener_access_summary);
+ map.put(PERMISSION_STORAGE, R.string.permission_storage_summary);
+ map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming_summary);
+ map.put(PERMISSION_PHONE, R.string.permission_phone_summary);
+ map.put(PERMISSION_SMS, R.string.permission_sms_summary);
+ map.put(PERMISSION_CONTACTS, R.string.permission_contacts_summary);
+ map.put(PERMISSION_CALENDAR, R.string.permission_calendar_summary);
+ map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices_summary);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
+ R.string.permission_nearby_device_streaming_summary);
+ map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary);
+ map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs_summary);
+ map.put(PERMISSION_NOTIFICATIONS, R.string.permission_notifications_summary);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control_summary);
+ PERMISSION_SUMMARIES = unmodifiableMap(map);
+ }
+
+ static final Map<Integer, Integer> PERMISSION_ICONS;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(PERMISSION_NOTIFICATION_LISTENER_ACCESS, R.drawable.ic_permission_notifications);
+ map.put(PERMISSION_STORAGE, R.drawable.ic_permission_storage);
+ map.put(PERMISSION_APP_STREAMING, R.drawable.ic_permission_app_streaming);
+ map.put(PERMISSION_PHONE, R.drawable.ic_permission_phone);
+ map.put(PERMISSION_SMS, R.drawable.ic_permission_sms);
+ map.put(PERMISSION_CONTACTS, R.drawable.ic_permission_contacts);
+ map.put(PERMISSION_CALENDAR, R.drawable.ic_permission_calendar);
+ map.put(PERMISSION_NEARBY_DEVICES, R.drawable.ic_permission_nearby_devices);
+ map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
+ R.drawable.ic_permission_nearby_device_streaming);
+ map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone);
+ map.put(PERMISSION_CALL_LOGS, R.drawable.ic_permission_call_logs);
+ map.put(PERMISSION_NOTIFICATIONS, R.drawable.ic_permission_notifications);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.drawable.ic_permission_media_routing_control);
+ PERMISSION_ICONS = unmodifiableMap(map);
+ }
+
+ // Profile resources
+ static final Map<String, Integer> PROFILE_TITLES;
static {
final Map<String, Integer> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_APP_STREAMING, R.string.title_app_streaming);
@@ -65,71 +130,61 @@ final class CompanionDeviceResources {
map.put(DEVICE_PROFILE_GLASSES, R.string.confirmation_title_glasses);
map.put(null, R.string.confirmation_title);
- TITLES = unmodifiableMap(map);
+ PROFILE_TITLES = unmodifiableMap(map);
+ }
+
+ static final Map<String, Integer> PROFILE_SUMMARIES;
+ static {
+ final Map<String, Integer> map = new ArrayMap<>();
+ map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch);
+ map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses);
+ map.put(null, R.string.summary_generic);
+
+ PROFILE_SUMMARIES = unmodifiableMap(map);
}
- static final Map<String, List<Integer>> PERMISSION_TYPES;
+ static final Map<String, List<Integer>> PROFILE_PERMISSIONS;
static {
final Map<String, List<Integer>> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_APP_STREAMING, Arrays.asList(PERMISSION_APP_STREAMING));
map.put(DEVICE_PROFILE_COMPUTER, Arrays.asList(
- PERMISSION_NOTIFICATION, PERMISSION_STORAGE));
+ PERMISSION_NOTIFICATION_LISTENER_ACCESS, PERMISSION_STORAGE));
map.put(DEVICE_PROFILE_NEARBY_DEVICE_STREAMING,
Arrays.asList(PERMISSION_NEARBY_DEVICE_STREAMING));
- if (!Flags.enablePrivilegedRoutingForMediaRoutingControl()) {
- map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
- PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
- PERMISSION_NEARBY_DEVICES));
- } else {
- map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
+ if (Build.VERSION.SDK_INT > UPSIDE_DOWN_CAKE) {
+ map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATIONS, PERMISSION_PHONE,
PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
PERMISSION_NEARBY_DEVICES, PERMISSION_CHANGE_MEDIA_OUTPUT));
+ } else {
+ map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
+ PERMISSION_PHONE, PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS,
+ PERMISSION_CALENDAR, PERMISSION_NEARBY_DEVICES));
}
- map.put(DEVICE_PROFILE_GLASSES, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
- PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_MICROPHONE,
+ map.put(DEVICE_PROFILE_GLASSES, Arrays.asList(PERMISSION_NOTIFICATION_LISTENER_ACCESS,
+ PERMISSION_PHONE, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_MICROPHONE,
PERMISSION_NEARBY_DEVICES));
- PERMISSION_TYPES = unmodifiableMap(map);
+ PROFILE_PERMISSIONS = unmodifiableMap(map);
}
- static final Map<String, Integer> SUMMARIES;
- static {
- final Map<String, Integer> map = new ArrayMap<>();
- map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch);
- map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses);
- map.put(null, R.string.summary_generic);
-
- SUMMARIES = unmodifiableMap(map);
- }
-
- static final Map<String, Integer> PROFILES_NAME;
+ static final Map<String, Integer> PROFILE_NAMES;
static {
final Map<String, Integer> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_WATCH, R.string.profile_name_watch);
map.put(DEVICE_PROFILE_GLASSES, R.string.profile_name_glasses);
map.put(null, R.string.profile_name_generic);
- PROFILES_NAME = unmodifiableMap(map);
- }
-
- static final Map<String, Integer> PROFILES_NAME_MULTI;
- static {
- final Map<String, Integer> map = new ArrayMap<>();
- map.put(DEVICE_PROFILE_GLASSES, R.string.profile_name_generic);
- map.put(DEVICE_PROFILE_WATCH, R.string.profile_name_watch);
- map.put(null, R.string.profile_name_generic);
-
- PROFILES_NAME_MULTI = unmodifiableMap(map);
+ PROFILE_NAMES = unmodifiableMap(map);
}
- static final Map<String, Integer> PROFILE_ICON;
+ static final Map<String, Integer> PROFILE_ICONS;
static {
final Map<String, Integer> map = new ArrayMap<>();
map.put(DEVICE_PROFILE_WATCH, R.drawable.ic_watch);
map.put(DEVICE_PROFILE_GLASSES, R.drawable.ic_glasses);
map.put(null, R.drawable.ic_device_other);
- PROFILE_ICON = unmodifiableMap(map);
+ PROFILE_ICONS = unmodifiableMap(map);
}
static final Set<String> SUPPORTED_PROFILES;
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index e21aee3cedb8..4a1f8014a2f0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -16,14 +16,14 @@
package com.android.companiondevicemanager;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_ICONS;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_SUMMARIES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_TITLES;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
import static com.android.companiondevicemanager.Utils.getIcon;
-import static java.util.Collections.unmodifiableMap;
-
import android.content.Context;
import android.text.Spanned;
-import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -35,7 +35,6 @@ import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
-import java.util.Map;
class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.ViewHolder> {
private final Context mContext;
@@ -43,75 +42,6 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
// Add the expand buttons if permissions are more than PERMISSION_SIZE in the permission list.
private static final int PERMISSION_SIZE = 2;
- static final int PERMISSION_NOTIFICATION = 0;
- static final int PERMISSION_STORAGE = 1;
- static final int PERMISSION_APP_STREAMING = 2;
- static final int PERMISSION_PHONE = 3;
- static final int PERMISSION_SMS = 4;
- static final int PERMISSION_CONTACTS = 5;
- static final int PERMISSION_CALENDAR = 6;
- static final int PERMISSION_NEARBY_DEVICES = 7;
- static final int PERMISSION_NEARBY_DEVICE_STREAMING = 8;
- static final int PERMISSION_MICROPHONE = 9;
- static final int PERMISSION_CALL_LOGS = 10;
- static final int PERMISSION_CHANGE_MEDIA_OUTPUT = 11;
-
- private static final Map<Integer, Integer> sTitleMap;
- static {
- final Map<Integer, Integer> map = new ArrayMap<>();
- map.put(PERMISSION_NOTIFICATION, R.string.permission_notification);
- map.put(PERMISSION_STORAGE, R.string.permission_storage);
- map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming);
- map.put(PERMISSION_PHONE, R.string.permission_phone);
- map.put(PERMISSION_SMS, R.string.permission_sms);
- map.put(PERMISSION_CONTACTS, R.string.permission_contacts);
- map.put(PERMISSION_CALENDAR, R.string.permission_calendar);
- map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices);
- map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming);
- map.put(PERMISSION_MICROPHONE, R.string.permission_microphone);
- map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs);
- map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control);
- sTitleMap = unmodifiableMap(map);
- }
-
- private static final Map<Integer, Integer> sSummaryMap;
- static {
- final Map<Integer, Integer> map = new ArrayMap<>();
- map.put(PERMISSION_NOTIFICATION, R.string.permission_notification_summary);
- map.put(PERMISSION_STORAGE, R.string.permission_storage_summary);
- map.put(PERMISSION_APP_STREAMING, R.string.permission_app_streaming_summary);
- map.put(PERMISSION_PHONE, R.string.permission_phone_summary);
- map.put(PERMISSION_SMS, R.string.permission_sms_summary);
- map.put(PERMISSION_CONTACTS, R.string.permission_contacts_summary);
- map.put(PERMISSION_CALENDAR, R.string.permission_calendar_summary);
- map.put(PERMISSION_NEARBY_DEVICES, R.string.permission_nearby_devices_summary);
- map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
- R.string.permission_nearby_device_streaming_summary);
- map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary);
- map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs_summary);
- map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control_summary);
- sSummaryMap = unmodifiableMap(map);
- }
-
- private static final Map<Integer, Integer> sIconMap;
- static {
- final Map<Integer, Integer> map = new ArrayMap<>();
- map.put(PERMISSION_NOTIFICATION, R.drawable.ic_permission_notifications);
- map.put(PERMISSION_STORAGE, R.drawable.ic_permission_storage);
- map.put(PERMISSION_APP_STREAMING, R.drawable.ic_permission_app_streaming);
- map.put(PERMISSION_PHONE, R.drawable.ic_permission_phone);
- map.put(PERMISSION_SMS, R.drawable.ic_permission_sms);
- map.put(PERMISSION_CONTACTS, R.drawable.ic_permission_contacts);
- map.put(PERMISSION_CALENDAR, R.drawable.ic_permission_calendar);
- map.put(PERMISSION_NEARBY_DEVICES, R.drawable.ic_permission_nearby_devices);
- map.put(PERMISSION_NEARBY_DEVICE_STREAMING,
- R.drawable.ic_permission_nearby_device_streaming);
- map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone);
- map.put(PERMISSION_CALL_LOGS, R.drawable.ic_permission_call_logs);
- map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.drawable.ic_permission_media_routing_control);
- sIconMap = unmodifiableMap(map);
- }
-
PermissionListAdapter(Context context) {
mContext = context;
}
@@ -121,7 +51,8 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_item_permission, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
- viewHolder.mPermissionIcon.setImageDrawable(getIcon(mContext, sIconMap.get(viewType)));
+ viewHolder.mPermissionIcon.setImageDrawable(
+ getIcon(mContext, PERMISSION_ICONS.get(viewType)));
if (viewHolder.mExpandButton.getTag() == null) {
viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more);
@@ -165,8 +96,8 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
int type = getItemViewType(position);
- final Spanned title = getHtmlFromResources(mContext, sTitleMap.get(type));
- final Spanned summary = getHtmlFromResources(mContext, sSummaryMap.get(type));
+ final Spanned title = getHtmlFromResources(mContext, PERMISSION_TITLES.get(type));
+ final Spanned summary = getHtmlFromResources(mContext, PERMISSION_SUMMARIES.get(type));
holder.mPermissionSummary.setText(summary);
holder.mPermissionName.setText(title);
@@ -192,6 +123,7 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
private final TextView mPermissionSummary;
private final ImageView mPermissionIcon;
private final ImageButton mExpandButton;
+
ViewHolder(View itemView) {
super(itemView);
mPermissionName = itemView.findViewById(R.id.permission_name);
@@ -203,7 +135,7 @@ class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.V
private void setAccessibility(View view, int viewType, int action, int statusResourceId,
int actionResourceId) {
- final String permission = mContext.getString(sTitleMap.get(viewType));
+ final String permission = mContext.getString(PERMISSION_TITLES.get(viewType));
if (actionResourceId != 0) {
view.announceForAccessibility(
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index e3b93ba34045..f4641b9930cb 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -202,11 +202,6 @@
<!-- Dialog attributes to indicate parse errors -->
<string name="Parse_error_dlg_text">There was a problem parsing the package.</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=30] -->
- <string name="wear_not_allowed_dlg_title">Android Wear</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=none] -->
- <string name="wear_not_allowed_dlg_text">Install/Uninstall actions not supported on Wear.</string>
-
<!-- Message that the app to be installed is being staged [CHAR LIMIT=50] -->
<string name="message_staging">Staging app&#8230;</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
index e07e9425808e..2da8c8c69ff8 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
@@ -156,10 +156,9 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
if (customUserManager.isUserOfType(USER_TYPE_PROFILE_MANAGED)
&& customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) {
messageBuilder.append(isArchive
- ? getString(R.string.archive_application_text_current_user_work_profile,
- userName) : getString(
- R.string.uninstall_application_text_current_user_work_profile,
- userName));
+ ? getString(R.string.archive_application_text_current_user_work_profile)
+ : getString(
+ R.string.uninstall_application_text_current_user_work_profile));
} else if (customUserManager.isUserOfType(USER_TYPE_PROFILE_CLONE)
&& customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) {
mIsClonedApp = true;
@@ -168,11 +167,11 @@ public class UninstallAlertDialogFragment extends DialogFragment implements
} else if (Flags.allowPrivateProfile()
&& customUserManager.isPrivateProfile()
&& customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) {
- messageBuilder.append(isArchive ? getString(
- R.string.archive_application_text_current_user_private_profile,
- userName) : getString(
- R.string.uninstall_application_text_current_user_private_profile,
- userName));
+ messageBuilder.append(
+ isArchive ? getString(
+ R.string.archive_application_text_current_user_private_profile)
+ : getString(
+ R.string.uninstall_application_text_current_user_private_profile));
} else if (isArchive) {
messageBuilder.append(
getString(R.string.archive_application_text_user, userName));
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 96a11eeb3b78..5b39f4ee1541 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -112,26 +112,6 @@ public class RestrictedLockUtils {
}
/**
- * Shows restricted setting dialog.
- */
- @RequiresApi(Build.VERSION_CODES.TIRAMISU)
- public static void sendShowRestrictedSettingDialogIntent(Context context,
- String packageName, int uid) {
- final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
- context.startActivity(intent);
- }
-
- /**
- * Gets restricted settings dialog intent.
- */
- private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
- final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- intent.putExtra(Intent.EXTRA_UID, uid);
- return intent;
- }
-
- /**
* Checks if current user is profile or not
*/
@RequiresApi(Build.VERSION_CODES.M)
@@ -238,4 +218,35 @@ public class RestrictedLockUtils {
+ '}';
}
}
+
+
+ /**
+ * Shows restricted setting dialog.
+ *
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public static void sendShowRestrictedSettingDialogIntent(Context context,
+ String packageName, int uid) {
+ final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Gets restricted settings dialog intent.
+ *
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
+ final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ return intent;
+ }
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
index f216abb66a64..66bd6f502274 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
@@ -28,7 +28,14 @@ import androidx.compose.material.icons.outlined.Shield
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
@@ -41,14 +48,14 @@ import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.widget.card.CardButton
import com.android.settingslib.spa.widget.card.CardModel
import com.android.settingslib.spa.widget.card.SettingsCard
-import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
import com.android.settingslib.spa.widget.card.SettingsCardContent
+import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
object CardPageProvider : SettingsPageProvider {
- override val name = "CardPage"
+ override val name = "Card"
override fun getTitle(arguments: Bundle?) = TITLE
@@ -79,10 +86,13 @@ object CardPageProvider : SettingsPageProvider {
@Composable
private fun SettingsCardWithoutIcon() {
+ var isVisible by rememberSaveable { mutableStateOf(true) }
SettingsCard(
CardModel(
title = stringResource(R.string.sample_title),
text = stringResource(R.string.sample_text),
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
buttons = listOf(
CardButton(text = "Action") {},
),
@@ -92,21 +102,23 @@ object CardPageProvider : SettingsPageProvider {
@Composable
fun SampleSettingsCollapsibleCard() {
- SettingsCollapsibleCard(
- title = "More alerts",
- imageVector = Icons.Outlined.Error,
- models = listOf(
+ val context = LocalContext.current
+ var isVisible0 by rememberSaveable { mutableStateOf(true) }
+ val cards = remember {
+ mutableStateListOf(
CardModel(
- title = stringResource(R.string.sample_title),
- text = stringResource(R.string.sample_text),
+ title = context.getString(R.string.sample_title),
+ text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.PowerOff,
+ isVisible = { isVisible0 },
+ onDismiss = { isVisible0 = false },
buttons = listOf(
CardButton(text = "Action") {},
)
),
CardModel(
- title = stringResource(R.string.sample_title),
- text = stringResource(R.string.sample_text),
+ title = context.getString(R.string.sample_title),
+ text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.Shield,
buttons = listOf(
CardButton(text = "Action") {},
@@ -114,6 +126,11 @@ object CardPageProvider : SettingsPageProvider {
)
)
)
+ }
+ SettingsCollapsibleCard(
+ title = "More alerts",
+ imageVector = Icons.Outlined.Error,
+ models = cards.toList()
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index c143390f269c..993cb4ac85e5 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -37,6 +37,7 @@ object SettingsDimension {
val itemPaddingAround = 8.dp
val itemDividerHeight = 32.dp
+ val iconSmall = 16.dp
val iconLarge = 48.dp
/** The size when app icon is displayed in list. */
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
index c113f4332fc3..b18a1bc01388 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
@@ -28,5 +28,14 @@ data class CardModel(
val title: String,
val text: String,
val imageVector: ImageVector? = null,
+ val isVisible: () -> Boolean = { true },
+
+ /**
+ * A dismiss button will be displayed if this is not null.
+ *
+ * And this callback will be called when user clicks the button.
+ */
+ val onDismiss: (() -> Unit)? = null,
+
val buttons: List<CardButton> = emptyList(),
)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
index 43792787c5aa..7eec8888f025 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
@@ -16,28 +16,35 @@
package com.android.settingslib.spa.widget.card
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.debug.UiModePreviews
import com.android.settingslib.spa.framework.theme.SettingsDimension
@@ -87,20 +94,31 @@ fun SettingsCard(model: CardModel) {
@Composable
internal fun SettingsCardImpl(model: CardModel) {
- SettingsCardContent {
- Column(
- modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
- verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
- ) {
- CardIcon(model.imageVector)
- SettingsTitle(model.title)
- SettingsBody(model.text)
- Buttons(model.buttons)
+ AnimatedVisibility(visible = model.isVisible()) {
+ SettingsCardContent {
+ Column(
+ modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
+ verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
+ ) {
+ CardHeader(model.imageVector, model.onDismiss)
+ SettingsTitle(model.title)
+ SettingsBody(model.text)
+ Buttons(model.buttons)
+ }
}
}
}
@Composable
+fun CardHeader(imageVector: ImageVector?, onDismiss: (() -> Unit)? = null) {
+ Row(Modifier.fillMaxWidth()) {
+ CardIcon(imageVector)
+ Spacer(modifier = Modifier.weight(1f))
+ DismissButton(onDismiss)
+ }
+}
+
+@Composable
private fun CardIcon(imageVector: ImageVector?) {
if (imageVector != null) {
Icon(
@@ -113,6 +131,28 @@ private fun CardIcon(imageVector: ImageVector?) {
}
@Composable
+private fun DismissButton(onDismiss: (() -> Unit)?) {
+ if (onDismiss == null) return
+ Surface(
+ shape = CircleShape,
+ color = MaterialTheme.colorScheme.secondaryContainer,
+ ) {
+ IconButton(
+ onClick = onDismiss,
+ modifier = Modifier.size(SettingsDimension.itemIconSize)
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Close,
+ contentDescription = stringResource(
+ androidx.compose.material3.R.string.m3c_snackbar_dismiss
+ ),
+ modifier = Modifier.size(SettingsDimension.iconSmall),
+ )
+ }
+ }
+}
+
+@Composable
private fun Buttons(buttons: List<CardButton>) {
if (buttons.isNotEmpty()) {
Row(
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
index bf192a18679e..6e36490beac7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
@@ -58,7 +58,7 @@ fun SettingsCollapsibleCard(
var expanded by rememberSaveable { mutableStateOf(false) }
SettingsCard {
SettingsCardContent {
- Header(title, imageVector, models.size, expanded) { expanded = it }
+ Header(title, imageVector, models.count { it.isVisible() }, expanded) { expanded = it }
}
AnimatedVisibility(expanded) {
Column {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
index fd3ae49d93c8..beb9433cdbf0 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
@@ -16,10 +16,18 @@
package com.android.settingslib.spa.widget.card
+import android.content.Context
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
@@ -31,6 +39,8 @@ class SettingsCardTest {
@get:Rule
val composeTestRule = createComposeRule()
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
@Test
fun settingsCard_titleDisplayed() {
composeTestRule.setContent {
@@ -96,6 +106,27 @@ class SettingsCardTest {
assertThat(buttonClicked).isTrue()
}
+ @Test
+ fun settingsCard_dismiss() {
+ composeTestRule.setContent {
+ var isVisible by remember { mutableStateOf(true) }
+ SettingsCard(
+ CardModel(
+ title = TITLE,
+ text = "",
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
+ )
+ )
+ }
+
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
+ ).performClick()
+
+ composeTestRule.onNodeWithText(TEXT).isNotDisplayed()
+ }
+
private companion object {
const val TITLE = "Title"
const val TEXT = "Text"
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
index efe1c701b1f6..aba9d7be1e91 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
@@ -16,12 +16,20 @@
package com.android.settingslib.spa.widget.card
+import android.content.Context
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Error
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
@@ -32,6 +40,8 @@ class SettingsCollapsibleCardTest {
@get:Rule
val composeTestRule = createComposeRule()
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
@Test
fun settingsCollapsibleCard_titleDisplayed() {
setContent()
@@ -62,8 +72,22 @@ class SettingsCollapsibleCardTest {
composeTestRule.onNodeWithText(CARD_TEXT).assertIsDisplayed()
}
+ @Test
+ fun settingsCollapsibleCard_dismiss() {
+ setContent()
+ composeTestRule.onNodeWithText(TITLE).performClick()
+
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
+ ).performClick()
+
+ composeTestRule.onNodeWithText(CARD_TEXT).isNotDisplayed()
+ composeTestRule.onNodeWithText("0").assertIsDisplayed()
+ }
+
private fun setContent() {
composeTestRule.setContent {
+ var isVisible by rememberSaveable { mutableStateOf(true) }
SettingsCollapsibleCard(
title = TITLE,
imageVector = Icons.Outlined.Error,
@@ -71,6 +95,8 @@ class SettingsCollapsibleCardTest {
CardModel(
title = "",
text = CARD_TEXT,
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
)
),
)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
index d0d2dc0083a6..e099f1124bf1 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
@@ -20,13 +20,17 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
+private const val TAG = "BroadcastReceiverFlow"
+
/**
* A [BroadcastReceiver] flow for the given [intentFilter].
*/
@@ -39,4 +43,6 @@ fun Context.broadcastReceiverFlow(intentFilter: IntentFilter): Flow<Intent> = ca
registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
awaitClose { unregisterReceiver(broadcastReceiver) }
+}.catch { e ->
+ Log.e(TAG, "Error while broadcastReceiverFlow", e)
}.conflate().flowOn(Dispatchers.Default)
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
index dfaf3c66ff8d..eef5225aef42 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
@@ -31,8 +31,10 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doThrow
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class BroadcastReceiverFlowTest {
@@ -74,6 +76,18 @@ class BroadcastReceiverFlowTest {
assertThat(onReceiveIsCalled).isTrue()
}
+ @Test
+ fun broadcastReceiverFlow_unregisterReceiverThrowException_noCrash() = runBlocking {
+ context.stub {
+ on { unregisterReceiver(any()) } doThrow IllegalArgumentException()
+ }
+ val flow = context.broadcastReceiverFlow(INTENT_FILTER)
+
+ flow.firstWithTimeoutOrNull()
+
+ assertThat(registeredBroadcastReceiver).isNotNull()
+ }
+
private companion object {
val INTENT_FILTER = IntentFilter()
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 4454b710b7e4..c51a9a07332f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -77,6 +77,9 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
ECM_KEYS.add(AppOpsManager.OPSTR_LOADER_USAGE_STATS);
ECM_KEYS.add(Manifest.permission.BIND_DEVICE_ADMIN);
}
+
+ ECM_KEYS.add(AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS);
+ ECM_KEYS.add(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
}
/**
@@ -291,32 +294,6 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
}
/**
- * Checks whether add user is disabled on the device
- *
- * @param context {@link Context} for the calling user.
- *
- *
- * @param userId User to check enforced admin status for.
- *
- * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
- * or {@code null} If adding user is not disabled.
- */
- public static EnforcedAdmin checkIfAddUserDisallowed(Context context, int userId) {
- final UserManager um = UserManager.get(context);
- if (!um.hasUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.of(userId))) {
- // Restriction is not enforced.
- return null;
- }
- EnforcedAdmin enforcedAdmin = checkIfRestrictionEnforced(context,
- UserManager.DISALLOW_ADD_USER, userId);
- if (enforcedAdmin != null) {
- return enforcedAdmin;
- }
- return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(
- UserManager.DISALLOW_ADD_USER);
- }
-
- /**
* Check if an application is suspended.
*
* @return EnforcedAdmin Object containing the enforced admin component and admin user details,
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index db2a6ec2da68..50e3bd08026c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -96,12 +96,29 @@ public class RestrictedPreference extends TwoTargetPreference {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
+ /**
+ * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this
+ * package. Marks the preference as disabled if so.
+ * @param restriction The key identifying the setting
+ * @param packageName the package to check the restriction for
+ * @param uid the uid of the package
+ */
+ public void checkEcmRestrictionAndSetDisabled(String restriction, String packageName, int uid) {
+ mHelper.checkEcmRestrictionAndSetDisabled(restriction, packageName, uid);
+ }
+
@Override
public void setEnabled(boolean enabled) {
if (enabled && isDisabledByAdmin()) {
mHelper.setDisabledByAdmin(null);
return;
}
+
+ if (enabled && isDisabledByEcm()) {
+ mHelper.setDisabledByEcm(null);
+ return;
+ }
+
super.setEnabled(enabled);
}
@@ -111,16 +128,14 @@ public class RestrictedPreference extends TwoTargetPreference {
}
}
- public void setDisabledByAppOps(boolean disabled) {
- if (mHelper.setDisabledByAppOps(disabled)) {
- notifyChanged();
- }
- }
-
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
+ public boolean isDisabledByEcm() {
+ return mHelper.isDisabledByEcm();
+ }
+
public int getUid() {
return mHelper != null ? mHelper.uid : Process.INVALID_UID;
}
@@ -128,4 +143,16 @@ public class RestrictedPreference extends TwoTargetPreference {
public String getPackageName() {
return mHelper != null ? mHelper.packageName : null;
}
+
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ public void setDisabledByAppOps(boolean disabled) {
+ if (mHelper.setDisabledByAppOps(disabled)) {
+ notifyChanged();
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 29ea25e13835..a479269f40fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -17,10 +17,12 @@
package com.android.settingslib;
import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTROLLED_BY_ADMIN_SUMMARY;
+
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.Intent;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.UserHandle;
@@ -52,7 +54,8 @@ public class RestrictedPreferenceHelper {
private String mAttrUserRestriction = null;
private boolean mDisabledSummary = false;
- private boolean mDisabledByAppOps;
+ private boolean mDisabledByEcm;
+ private Intent mDisabledByEcmIntent = null;
public RestrictedPreferenceHelper(Context context, Preference preference,
AttributeSet attrs, String packageName, int uid) {
@@ -101,7 +104,7 @@ public class RestrictedPreferenceHelper {
* Modify PreferenceViewHolder to add padlock if restriction is disabled.
*/
public void onBindViewHolder(PreferenceViewHolder holder) {
- if (mDisabledByAdmin || mDisabledByAppOps) {
+ if (mDisabledByAdmin || mDisabledByEcm) {
holder.itemView.setEnabled(true);
}
if (mDisabledSummary) {
@@ -112,7 +115,7 @@ public class RestrictedPreferenceHelper {
: mContext.getString(R.string.disabled_by_admin_summary_text);
if (mDisabledByAdmin) {
summaryView.setText(disabledText);
- } else if (mDisabledByAppOps) {
+ } else if (mDisabledByEcm) {
summaryView.setText(R.string.disabled_by_app_ops_text);
} else if (TextUtils.equals(disabledText, summaryView.getText())) {
// It's previously set to disabled text, clear it.
@@ -144,7 +147,12 @@ public class RestrictedPreferenceHelper {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mEnforcedAdmin);
return true;
}
- if (mDisabledByAppOps) {
+ if (mDisabledByEcm) {
+ if (android.security.Flags.extendEcmToAllSettings()) {
+ mContext.startActivity(mDisabledByEcmIntent);
+ return true;
+ }
+
RestrictedLockUtilsInternal.sendShowRestrictedSettingDialogIntent(mContext, packageName,
uid);
return true;
@@ -174,6 +182,20 @@ public class RestrictedPreferenceHelper {
}
/**
+ * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this
+ * package. Marks the preference as disabled if so.
+ * @param restriction The key identifying the setting
+ * @param packageName the package to check the restriction for
+ * @param uid the uid of the package
+ */
+ public void checkEcmRestrictionAndSetDisabled(String restriction, String packageName, int uid) {
+ updatePackageDetails(packageName, uid);
+ Intent intent = RestrictedLockUtilsInternal.checkIfRequiresEnhancedConfirmation(
+ mContext, restriction, uid, packageName);
+ setDisabledByEcm(intent);
+ }
+
+ /**
* @return EnforcedAdmin if we have been passed the restriction in the xml.
*/
public EnforcedAdmin checkRestrictionEnforced() {
@@ -211,10 +233,19 @@ public class RestrictedPreferenceHelper {
return changed;
}
- public boolean setDisabledByAppOps(boolean disabled) {
+ /**
+ * Disable the preference based on the passed in Intent
+ * @param disabledIntent The intent which is started when the user clicks the disabled
+ * preference. If it is {@code null}, then this preference will be enabled. Otherwise, it will
+ * be disabled.
+ * @return true if the disabled state was changed.
+ */
+ public boolean setDisabledByEcm(Intent disabledIntent) {
+ boolean disabled = disabledIntent != null;
boolean changed = false;
- if (mDisabledByAppOps != disabled) {
- mDisabledByAppOps = disabled;
+ if (mDisabledByEcm != disabled) {
+ mDisabledByEcmIntent = disabledIntent;
+ mDisabledByEcm = disabled;
changed = true;
updateDisabledState();
}
@@ -226,8 +257,8 @@ public class RestrictedPreferenceHelper {
return mDisabledByAdmin;
}
- public boolean isDisabledByAppOps() {
- return mDisabledByAppOps;
+ public boolean isDisabledByEcm() {
+ return mDisabledByEcm;
}
public void updatePackageDetails(String packageName, int uid) {
@@ -236,13 +267,31 @@ public class RestrictedPreferenceHelper {
}
private void updateDisabledState() {
+ boolean isEnabled = !(mDisabledByAdmin || mDisabledByEcm);
if (!(mPreference instanceof RestrictedTopLevelPreference)) {
- mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
+ mPreference.setEnabled(isEnabled);
}
if (mPreference instanceof PrimarySwitchPreference) {
- ((PrimarySwitchPreference) mPreference)
- .setSwitchEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
+ ((PrimarySwitchPreference) mPreference).setSwitchEnabled(isEnabled);
}
}
+
+
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
+ public boolean setDisabledByAppOps(boolean disabled) {
+ boolean changed = false;
+ if (mDisabledByEcm != disabled) {
+ mDisabledByEcm = disabled;
+ changed = true;
+ updateDisabledState();
+ }
+
+ return changed;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 60321eb1a9dc..3b8f66577f6e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -197,6 +197,17 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
+ /**
+ * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this
+ * package. Marks the preference as disabled if so.
+ * @param restriction The key identifying the setting
+ * @param packageName the package to check the restriction for
+ * @param uid the uid of the package
+ */
+ public void checkEcmRestrictionAndSetDisabled(String restriction, String packageName, int uid) {
+ mHelper.checkEcmRestrictionAndSetDisabled(restriction, packageName, uid);
+ }
+
@Override
public void setEnabled(boolean enabled) {
boolean changed = false;
@@ -204,8 +215,8 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
mHelper.setDisabledByAdmin(null);
changed = true;
}
- if (enabled && isDisabledByAppOps()) {
- mHelper.setDisabledByAppOps(false);
+ if (enabled && isDisabledByEcm()) {
+ mHelper.setDisabledByEcm(null);
changed = true;
}
if (!changed) {
@@ -223,25 +234,50 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
return mHelper.isDisabledByAdmin();
}
+ public boolean isDisabledByEcm() {
+ return mHelper.isDisabledByEcm();
+ }
+
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
private void setDisabledByAppOps(boolean disabled) {
if (mHelper.setDisabledByAppOps(disabled)) {
notifyChanged();
}
}
- public boolean isDisabledByAppOps() {
- return mHelper.isDisabledByAppOps();
- }
-
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
public int getUid() {
return mHelper != null ? mHelper.uid : Process.INVALID_UID;
}
+ /**
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
public String getPackageName() {
return mHelper != null ? mHelper.packageName : null;
}
- /** Updates enabled state based on associated package. */
+ /**
+ * Updates enabled state based on associated package
+ *
+ * @deprecated TODO(b/308921175): This will be deleted with the
+ * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
+ * code.
+ */
+ @Deprecated
public void updateState(
@NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
mHelper.updatePackageDetails(packageName, uid);
@@ -258,7 +294,7 @@ public class RestrictedSwitchPreference extends SwitchPreferenceCompat {
setEnabled(false);
} else if (isEnabled) {
setEnabled(true);
- } else if (appOpsAllowed && isDisabledByAppOps()) {
+ } else if (appOpsAllowed && isDisabledByEcm()) {
setEnabled(true);
} else if (!appOpsAllowed){
setDisabledByAppOps(true);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 69b61c74625e..49ac0f864ed7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -28,10 +28,11 @@ import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.bluetooth.BluetoothLeBroadcastSettings;
import android.bluetooth.BluetoothLeBroadcastSubgroup;
+import android.bluetooth.BluetoothLeBroadcastSubgroupSettings;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.bluetooth.BluetoothStatusCodes;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -42,26 +43,30 @@ import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.settingslib.R;
+import com.google.common.collect.ImmutableList;
+
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
/**
- * LocalBluetoothLeBroadcast provides an interface between the Settings app
- * and the functionality of the local {@link BluetoothLeBroadcast}.
- * Use the {@link BluetoothLeBroadcast.Callback} to get the result callback.
+ * LocalBluetoothLeBroadcast provides an interface between the Settings app and the functionality of
+ * the local {@link BluetoothLeBroadcast}. Use the {@link BluetoothLeBroadcast.Callback} to get the
+ * result callback.
*/
public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
private static final String TAG = "LocalBluetoothLeBroadcast";
@@ -74,11 +79,12 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
// Order of this profile in device profiles list
private static final int ORDINAL = 1;
private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
- private static final Uri[] SETTINGS_URIS = new Uri[]{
- Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO),
- Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE),
- Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
- };
+ private static final Uri[] SETTINGS_URIS =
+ new Uri[] {
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO),
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE),
+ Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
+ };
private BluetoothLeBroadcast mServiceBroadcast;
private BluetoothLeBroadcastAssistant mServiceBroadcastAssistant;
@@ -95,62 +101,82 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
private Executor mExecutor;
private ContentResolver mContentResolver;
private ContentObserver mSettingsObserver;
+ // Cached broadcast callbacks being register before service is connected.
+ private Map<BluetoothLeBroadcast.Callback, Executor> mCachedBroadcastCallbackExecutorMap =
+ new ConcurrentHashMap<>();
- private final ServiceListener mServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service connected: " + profile);
- }
- if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && !mIsBroadcastProfileReady) {
- mServiceBroadcast = (BluetoothLeBroadcast) proxy;
- mIsBroadcastProfileReady = true;
- registerServiceCallBack(mExecutor, mBroadcastCallback);
- List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
- if (!metadata.isEmpty()) {
- updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
+ private final ServiceListener mServiceListener =
+ new ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service connected: " + profile);
+ }
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST)
+ && !mIsBroadcastProfileReady) {
+ mServiceBroadcast = (BluetoothLeBroadcast) proxy;
+ mIsBroadcastProfileReady = true;
+ registerServiceCallBack(mExecutor, mBroadcastCallback);
+ List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
+ if (!metadata.isEmpty()) {
+ updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
+ }
+ registerContentObserver();
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onServiceConnected: register "
+ + "mCachedBroadcastCallbackExecutorMap = "
+ + mCachedBroadcastCallbackExecutorMap);
+ }
+ mCachedBroadcastCallbackExecutorMap.forEach(
+ (callback, executor) ->
+ registerServiceCallBack(executor, callback));
+ } else if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ && !mIsBroadcastAssistantProfileReady) {
+ mIsBroadcastAssistantProfileReady = true;
+ mServiceBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
+ registerBroadcastAssistantCallback(mExecutor, mBroadcastAssistantCallback);
+ }
}
- registerContentObserver();
- } else if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
- && !mIsBroadcastAssistantProfileReady) {
- mIsBroadcastAssistantProfileReady = true;
- mServiceBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
- registerBroadcastAssistantCallback(mExecutor, mBroadcastAssistantCallback);
- }
- }
- @Override
- public void onServiceDisconnected(int profile) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service disconnected");
- }
- if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST) && mIsBroadcastProfileReady) {
- mIsBroadcastProfileReady = false;
- unregisterServiceCallBack(mBroadcastCallback);
- }
- if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
- && mIsBroadcastAssistantProfileReady) {
- mIsBroadcastAssistantProfileReady = false;
- unregisterBroadcastAssistantCallback(mBroadcastAssistantCallback);
- }
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service disconnected: " + profile);
+ }
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST)
+ && mIsBroadcastProfileReady) {
+ mIsBroadcastProfileReady = false;
+ unregisterServiceCallBack(mBroadcastCallback);
+ mCachedBroadcastCallbackExecutorMap.clear();
+ }
+ if ((profile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ && mIsBroadcastAssistantProfileReady) {
+ mIsBroadcastAssistantProfileReady = false;
+ unregisterBroadcastAssistantCallback(mBroadcastAssistantCallback);
+ }
- if (!mIsBroadcastAssistantProfileReady && !mIsBroadcastProfileReady) {
- unregisterContentObserver();
- }
- }
- };
+ if (!mIsBroadcastAssistantProfileReady && !mIsBroadcastProfileReady) {
+ unregisterContentObserver();
+ }
+ }
+ };
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
new BluetoothLeBroadcast.Callback() {
@Override
public void onBroadcastStarted(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastStarted(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastStarted(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
setLatestBroadcastId(broadcastId);
- setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
+ setAppSourceName(mNewAppSourceName, /* updateContentResolver= */ true);
}
@Override
@@ -161,8 +187,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
@Override
- public void onBroadcastMetadataChanged(int broadcastId,
- @NonNull BluetoothLeBroadcastMetadata metadata) {
+ public void onBroadcastMetadataChanged(
+ int broadcastId, @NonNull BluetoothLeBroadcastMetadata metadata) {
if (DEBUG) {
Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId);
}
@@ -172,8 +198,11 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
@Override
public void onBroadcastStopped(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastStopped(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastStopped(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
@@ -191,37 +220,42 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
@Override
public void onBroadcastUpdated(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastUpdated(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastUpdated(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
setLatestBroadcastId(broadcastId);
- setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
+ setAppSourceName(mNewAppSourceName, /* updateContentResolver= */ true);
}
@Override
public void onBroadcastUpdateFailed(int reason, int broadcastId) {
if (DEBUG) {
- Log.d(TAG,
- "onBroadcastUpdateFailed(), reason = " + reason + ", broadcastId = "
+ Log.d(
+ TAG,
+ "onBroadcastUpdateFailed(), reason = "
+ + reason
+ + ", broadcastId = "
+ broadcastId);
}
}
@Override
- public void onPlaybackStarted(int reason, int broadcastId) {
- }
+ public void onPlaybackStarted(int reason, int broadcastId) {}
@Override
- public void onPlaybackStopped(int reason, int broadcastId) {
- }
+ public void onPlaybackStopped(int reason, int broadcastId) {}
};
private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
new BluetoothLeBroadcastAssistant.Callback() {
@Override
- public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {}
+ public void onSourceAdded(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {}
+
@Override
public void onSearchStarted(int reason) {}
@@ -238,38 +272,65 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {}
@Override
- public void onSourceAddFailed(@NonNull BluetoothDevice sink,
- @NonNull BluetoothLeBroadcastMetadata source, int reason) {}
+ public void onSourceAddFailed(
+ @NonNull BluetoothDevice sink,
+ @NonNull BluetoothLeBroadcastMetadata source,
+ int reason) {}
@Override
- public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {}
+ public void onSourceModified(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {}
@Override
- public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {}
+ public void onSourceModifyFailed(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {}
@Override
- public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {
+ public void onSourceRemoved(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {
if (DEBUG) {
- Log.d(TAG, "onSourceRemoved(), sink = " + sink + ", reason = "
- + reason + ", sourceId = " + sourceId);
+ Log.d(
+ TAG,
+ "onSourceRemoved(), sink = "
+ + sink
+ + ", reason = "
+ + reason
+ + ", sourceId = "
+ + sourceId);
}
}
@Override
- public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId,
- int reason) {
+ public void onSourceRemoveFailed(
+ @NonNull BluetoothDevice sink, int sourceId, int reason) {
if (DEBUG) {
- Log.d(TAG, "onSourceRemoveFailed(), sink = " + sink + ", reason = "
- + reason + ", sourceId = " + sourceId);
+ Log.d(
+ TAG,
+ "onSourceRemoveFailed(), sink = "
+ + sink
+ + ", reason = "
+ + reason
+ + ", sourceId = "
+ + sourceId);
}
}
@Override
- public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
- @NonNull BluetoothLeBroadcastReceiveState state) {}
+ public void onReceiveStateChanged(
+ @NonNull BluetoothDevice sink,
+ int sourceId,
+ @NonNull BluetoothLeBroadcastReceiveState state) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onReceiveStateChanged(), sink = "
+ + sink
+ + ", sourceId = "
+ + sourceId
+ + ", state = "
+ + state);
+ }
+ }
};
private class BroadcastSettingsObserver extends ContentObserver {
@@ -296,8 +357,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
BluetoothAdapter.getDefaultAdapter()
.getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
BluetoothAdapter.getDefaultAdapter()
- .getProfileProxy(context, mServiceListener,
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+ .getProfileProxy(
+ context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
}
/**
@@ -312,20 +373,91 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
String programInfo = getProgramInfo();
if (DEBUG) {
- Log.d(TAG,
- "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
+ Log.d(TAG, "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
buildContentMetadata(language, programInfo);
- mServiceBroadcast.startBroadcast(mBluetoothLeAudioContentMetadata,
+ mServiceBroadcast.startBroadcast(
+ mBluetoothLeAudioContentMetadata,
(mBroadcastCode != null && mBroadcastCode.length > 0) ? mBroadcastCode : null);
}
+ /**
+ * Start the private Broadcast for personal audio sharing or qr code sharing.
+ *
+ * <p>The broadcast will use random string for both broadcast name and subgroup program info;
+ * The broadcast will use random string for broadcast code; The broadcast will only have one
+ * subgroup due to system limitation; The subgroup language will be null.
+ *
+ * <p>If the system started the LE Broadcast, then the system calls the corresponding callback
+ * {@link BluetoothLeBroadcast.Callback}.
+ */
+ public void startPrivateBroadcast(int quality) {
+ mNewAppSourceName = "Sharing audio";
+ if (mServiceBroadcast == null) {
+ Log.d(TAG, "The BluetoothLeBroadcast is null when starting the private broadcast.");
+ return;
+ }
+ if (mServiceBroadcast.getAllBroadcastMetadata().size()
+ >= mServiceBroadcast.getMaximumNumberOfBroadcasts()) {
+ Log.d(TAG, "Skip starting the broadcast due to number limit.");
+ return;
+ }
+ String programInfo = getProgramInfo();
+ if (DEBUG) {
+ Log.d(TAG, "startBroadcast: language = null ,programInfo = " + programInfo);
+ }
+ // Current broadcast framework only support one subgroup
+ BluetoothLeBroadcastSubgroupSettings subgroupSettings =
+ buildBroadcastSubgroupSettings(/* language= */ null, programInfo, quality);
+ BluetoothLeBroadcastSettings settings =
+ buildBroadcastSettings(
+ true, // TODO: set to false after framework fix
+ TextUtils.isEmpty(programInfo) ? null : programInfo,
+ (mBroadcastCode != null && mBroadcastCode.length > 0)
+ ? mBroadcastCode
+ : null,
+ ImmutableList.of(subgroupSettings));
+ mServiceBroadcast.startBroadcast(settings);
+ }
+
+ private BluetoothLeBroadcastSettings buildBroadcastSettings(
+ boolean isPublic,
+ @Nullable String broadcastName,
+ @Nullable byte[] broadcastCode,
+ List<BluetoothLeBroadcastSubgroupSettings> subgroupSettingsList) {
+ BluetoothLeBroadcastSettings.Builder builder =
+ new BluetoothLeBroadcastSettings.Builder()
+ .setPublicBroadcast(isPublic)
+ .setBroadcastName(broadcastName)
+ .setBroadcastCode(broadcastCode);
+ for (BluetoothLeBroadcastSubgroupSettings subgroupSettings : subgroupSettingsList) {
+ builder.addSubgroupSettings(subgroupSettings);
+ }
+ return builder.build();
+ }
+
+ private BluetoothLeBroadcastSubgroupSettings buildBroadcastSubgroupSettings(
+ @Nullable String language, @Nullable String programInfo, int quality) {
+ BluetoothLeAudioContentMetadata metadata =
+ new BluetoothLeAudioContentMetadata.Builder()
+ .setLanguage(language)
+ .setProgramInfo(programInfo)
+ .build();
+ // Current broadcast framework only support one subgroup, thus we still maintain the latest
+ // metadata to keep legacy UI working.
+ mBluetoothLeAudioContentMetadata = metadata;
+ return new BluetoothLeBroadcastSubgroupSettings.Builder()
+ .setPreferredQuality(quality)
+ .setContentMetadata(mBluetoothLeAudioContentMetadata)
+ .build();
+ }
+
public String getProgramInfo() {
return mProgramInfo;
}
public void setProgramInfo(String programInfo) {
- setProgramInfo(programInfo, /*updateContentResolver=*/ true);
+ setProgramInfo(programInfo, /* updateContentResolver= */ true);
}
private void setProgramInfo(String programInfo, boolean updateContentResolver) {
@@ -344,8 +476,10 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "mContentResolver is null");
return;
}
- Settings.Secure.putString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, programInfo);
+ Settings.Secure.putString(
+ mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO,
+ programInfo);
}
}
@@ -354,7 +488,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
public void setBroadcastCode(byte[] broadcastCode) {
- setBroadcastCode(broadcastCode, /*updateContentResolver=*/ true);
+ setBroadcastCode(broadcastCode, /* updateContentResolver= */ true);
}
private void setBroadcastCode(byte[] broadcastCode, boolean updateContentResolver) {
@@ -372,7 +506,9 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "mContentResolver is null");
return;
}
- Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
+ Settings.Secure.putString(
+ mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
new String(broadcastCode, StandardCharsets.UTF_8));
}
}
@@ -401,8 +537,10 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "mContentResolver is null");
return;
}
- Settings.Secure.putString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, mAppSourceName);
+ Settings.Secure.putString(
+ mContentResolver,
+ Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME,
+ mAppSourceName);
}
}
@@ -427,10 +565,11 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
if (mBluetoothLeBroadcastMetadata == null) {
final List<BluetoothLeBroadcastMetadata> metadataList =
mServiceBroadcast.getAllBroadcastMetadata();
- mBluetoothLeBroadcastMetadata = metadataList.stream()
- .filter(i -> i.getBroadcastId() == mBroadcastId)
- .findFirst()
- .orElse(null);
+ mBluetoothLeBroadcastMetadata =
+ metadataList.stream()
+ .filter(i -> i.getBroadcastId() == mBroadcastId)
+ .findFirst()
+ .orElse(null);
}
return mBluetoothLeBroadcastMetadata;
}
@@ -440,22 +579,27 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
Log.d(TAG, "updateBroadcastInfoFromContentProvider: mContentResolver is null");
return;
}
- String programInfo = Settings.Secure.getString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO);
+ String programInfo =
+ Settings.Secure.getString(
+ mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO);
if (programInfo == null) {
programInfo = getDefaultValueOfProgramInfo();
}
- setProgramInfo(programInfo, /*updateContentResolver=*/ false);
+ setProgramInfo(programInfo, /* updateContentResolver= */ false);
- String prefBroadcastCode = Settings.Secure.getString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE);
- byte[] broadcastCode = (prefBroadcastCode == null) ? getDefaultValueOfBroadcastCode()
- : prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
- setBroadcastCode(broadcastCode, /*updateContentResolver=*/ false);
+ String prefBroadcastCode =
+ Settings.Secure.getString(
+ mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE);
+ byte[] broadcastCode =
+ (prefBroadcastCode == null)
+ ? getDefaultValueOfBroadcastCode()
+ : prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
+ setBroadcastCode(broadcastCode, /* updateContentResolver= */ false);
- String appSourceName = Settings.Secure.getString(mContentResolver,
- Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME);
- setAppSourceName(appSourceName, /*updateContentResolver=*/ false);
+ String appSourceName =
+ Settings.Secure.getString(
+ mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME);
+ setAppSourceName(appSourceName, /* updateContentResolver= */ false);
}
private void updateBroadcastInfoFromBroadcastMetadata(
@@ -474,12 +618,12 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
BluetoothLeAudioContentMetadata contentMetadata = subgroup.get(0).getContentMetadata();
setProgramInfo(contentMetadata.getProgramInfo());
- setAppSourceName(getAppSourceName(), /*updateContentResolver=*/ true);
+ setAppSourceName(getAppSourceName(), /* updateContentResolver= */ true);
}
/**
- * Stop the latest LE Broadcast. If the system stopped the LE Broadcast, then the system
- * calls the corresponding callback {@link BluetoothLeBroadcast.Callback}.
+ * Stop the latest LE Broadcast. If the system stopped the LE Broadcast, then the system calls
+ * the corresponding callback {@link BluetoothLeBroadcast.Callback}.
*/
public void stopLatestBroadcast() {
stopBroadcast(mBroadcastId);
@@ -511,7 +655,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
String programInfo = getProgramInfo();
if (DEBUG) {
- Log.d(TAG,
+ Log.d(
+ TAG,
"updateBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
mNewAppSourceName = appSourceName;
@@ -519,50 +664,79 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
mServiceBroadcast.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
}
- public void registerServiceCallBack(@NonNull @CallbackExecutor Executor executor,
+ /**
+ * Register Broadcast Callbacks to track its state and receivers
+ *
+ * @param executor Executor object for callback
+ * @param callback Callback object to be registered
+ */
+ public void registerServiceCallBack(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcast.Callback callback) {
if (mServiceBroadcast == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(TAG, "registerServiceCallBack failed, the BluetoothLeBroadcast is null.");
+ mCachedBroadcastCallbackExecutorMap.putIfAbsent(callback, executor);
return;
}
- mServiceBroadcast.registerCallback(executor, callback);
+ try {
+ mServiceBroadcast.registerCallback(executor, callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "registerServiceCallBack failed. " + e.getMessage());
+ }
}
/**
- * Register Broadcast Assistant Callbacks to track it's state and receivers
+ * Register Broadcast Assistant Callbacks to track its state and receivers
*
* @param executor Executor object for callback
* @param callback Callback object to be registered
*/
- public void registerBroadcastAssistantCallback(@NonNull @CallbackExecutor Executor executor,
+ private void registerBroadcastAssistantCallback(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
if (mServiceBroadcastAssistant == null) {
- Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
+ Log.d(
+ TAG,
+ "registerBroadcastAssistantCallback failed, "
+ + "the BluetoothLeBroadcastAssistant is null.");
return;
}
mServiceBroadcastAssistant.registerCallback(executor, callback);
}
+ /**
+ * Unregister previously registered Broadcast Callbacks
+ *
+ * @param callback Callback object to be unregistered
+ */
public void unregisterServiceCallBack(@NonNull BluetoothLeBroadcast.Callback callback) {
+ mCachedBroadcastCallbackExecutorMap.remove(callback);
if (mServiceBroadcast == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(TAG, "unregisterServiceCallBack failed, the BluetoothLeBroadcast is null.");
return;
}
- mServiceBroadcast.unregisterCallback(callback);
+ try {
+ mServiceBroadcast.unregisterCallback(callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "unregisterServiceCallBack failed. " + e.getMessage());
+ }
}
/**
- * Unregister previousely registered Broadcast Assistant Callbacks
+ * Unregister previously registered Broadcast Assistant Callbacks
*
* @param callback Callback object to be unregistered
*/
- public void unregisterBroadcastAssistantCallback(
+ private void unregisterBroadcastAssistantCallback(
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
if (mServiceBroadcastAssistant == null) {
- Log.d(TAG, "The BluetoothLeBroadcastAssisntant is null.");
+ Log.d(
+ TAG,
+ "unregisterBroadcastAssistantCallback, "
+ + "the BluetoothLeBroadcastAssistant is null.");
return;
}
@@ -570,8 +744,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
private void buildContentMetadata(String language, String programInfo) {
- mBluetoothLeAudioContentMetadata = mBuilder.setLanguage(language).setProgramInfo(
- programInfo).build();
+ mBluetoothLeAudioContentMetadata =
+ mBuilder.setLanguage(language).setProgramInfo(programInfo).build();
}
public LocalBluetoothLeBroadcastMetadata getLocalBluetoothLeBroadcastMetaData() {
@@ -600,9 +774,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return true;
}
- /**
- * Not supported since LE Audio Broadcasts do not establish a connection.
- */
+ /** Not supported since LE Audio Broadcasts do not establish a connection. */
public int getConnectionStatus(BluetoothDevice device) {
if (mServiceBroadcast == null) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -611,9 +783,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return mServiceBroadcast.getConnectionState(device);
}
- /**
- * Not supported since LE Audio Broadcasts do not establish a connection.
- */
+ /** Not supported since LE Audio Broadcasts do not establish a connection. */
public List<BluetoothDevice> getConnectedDevices() {
if (mServiceBroadcast == null) {
return new ArrayList<BluetoothDevice>(0);
@@ -622,8 +792,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return mServiceBroadcast.getConnectedDevices();
}
- public @NonNull
- List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
+ /** Get all broadcast metadata. */
+ public @NonNull List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata() {
if (mServiceBroadcast == null) {
Log.d(TAG, "The BluetoothLeBroadcast is null.");
return Collections.emptyList();
@@ -640,16 +810,14 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
return !mServiceBroadcast.getAllBroadcastMetadata().isEmpty();
}
- /**
- * Service does not provide method to get/set policy.
- */
+ /** Service does not provide method to get/set policy. */
public int getConnectionPolicy(BluetoothDevice device) {
return CONNECTION_POLICY_FORBIDDEN;
}
/**
- * Service does not provide "setEnabled" method. Please use {@link #startBroadcast},
- * {@link #stopBroadcast()} or {@link #updateBroadcast(String, String)}
+ * Service does not provide "setEnabled" method. Please use {@link #startBroadcast}, {@link
+ * #stopBroadcast()} or {@link #updateBroadcast(String, String)}
*/
public boolean setEnabled(BluetoothDevice device, boolean enabled) {
return false;
@@ -683,9 +851,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
if (mServiceBroadcast != null) {
try {
- BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
- BluetoothProfile.LE_AUDIO_BROADCAST,
- mServiceBroadcast);
+ BluetoothAdapter.getDefaultAdapter()
+ .closeProfileProxy(BluetoothProfile.LE_AUDIO_BROADCAST, mServiceBroadcast);
mServiceBroadcast = null;
} catch (Throwable t) {
Log.w(TAG, "Error cleaning up LeAudio proxy", t);
@@ -694,13 +861,13 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
private String getDefaultValueOfProgramInfo() {
- //set the default value;
+ // set the default value;
int postfix = ThreadLocalRandom.current().nextInt(DEFAULT_CODE_MIN, DEFAULT_CODE_MAX);
return BluetoothAdapter.getDefaultAdapter().getName() + UNDERLINE + postfix;
}
private byte[] getDefaultValueOfBroadcastCode() {
- //set the default value;
+ // set the default value;
return generateRandomPassword().getBytes(StandardCharsets.UTF_8);
}
@@ -708,14 +875,14 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
if (DEBUG) {
Log.d(TAG, "resetCacheInfo:");
}
- setAppSourceName("", /*updateContentResolver=*/ true);
+ setAppSourceName("", /* updateContentResolver= */ true);
mBluetoothLeBroadcastMetadata = null;
mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
}
private String generateRandomPassword() {
String randomUUID = UUID.randomUUID().toString();
- //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+ // first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
return randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
}
@@ -752,5 +919,4 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
}
}
}
-
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
index bb103b8896fd..34008ac56042 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
@@ -39,13 +39,14 @@ import com.android.settingslib.R;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
-
/**
- * LocalBluetoothLeBroadcastAssistant provides an interface between the Settings app
- * and the functionality of the local {@link BluetoothLeBroadcastAssistant}.
- * Use the {@link BluetoothLeBroadcastAssistant.Callback} to get the result callback.
+ * LocalBluetoothLeBroadcastAssistant provides an interface between the Settings app and the
+ * functionality of the local {@link BluetoothLeBroadcastAssistant}. Use the {@link
+ * BluetoothLeBroadcastAssistant.Callback} to get the result callback.
*/
public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile {
private static final String TAG = "LocalBluetoothLeBroadcastAssistant";
@@ -62,58 +63,76 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
private BluetoothLeBroadcastMetadata.Builder mBuilder;
private boolean mIsProfileReady;
+ // Cached assistant callbacks being register before service is connected.
+ private final Map<BluetoothLeBroadcastAssistant.Callback, Executor> mCachedCallbackExecutorMap =
+ new ConcurrentHashMap<>();
+
+ private final ServiceListener mServiceListener =
+ new ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service connected");
+ }
+ mService = (BluetoothLeBroadcastAssistant) proxy;
+ // We just bound to the service, so refresh the UI for any connected LeAudio
+ // devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "LocalBluetoothLeBroadcastAssistant found new device: "
+ + nextDevice);
+ }
+ device = mDeviceManager.addDevice(nextDevice);
+ }
+ device.onProfileStateChanged(
+ LocalBluetoothLeBroadcastAssistant.this,
+ BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
- private final ServiceListener mServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service connected");
- }
- mService = (BluetoothLeBroadcastAssistant) proxy;
- // We just bound to the service, so refresh the UI for any connected LeAudio devices.
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- while (!deviceList.isEmpty()) {
- BluetoothDevice nextDevice = deviceList.remove(0);
- CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
- // we may add a new device here, but generally this should not happen
- if (device == null) {
+ mProfileManager.callServiceConnectedListeners();
+ mIsProfileReady = true;
if (DEBUG) {
- Log.d(TAG, "LocalBluetoothLeBroadcastAssistant found new device: "
- + nextDevice);
+ Log.d(
+ TAG,
+ "onServiceConnected, register mCachedCallbackExecutorMap = "
+ + mCachedCallbackExecutorMap);
}
- device = mDeviceManager.addDevice(nextDevice);
+ mCachedCallbackExecutorMap.forEach(
+ (callback, executor) -> registerServiceCallBack(executor, callback));
}
- device.onProfileStateChanged(LocalBluetoothLeBroadcastAssistant.this,
- BluetoothProfile.STATE_CONNECTED);
- device.refresh();
- }
- mProfileManager.callServiceConnectedListeners();
- mIsProfileReady = true;
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- if (profile != BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT) {
- Log.d(TAG, "The profile is not LE_AUDIO_BROADCAST_ASSISTANT");
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service disconnected");
- }
- mProfileManager.callServiceDisconnectedListeners();
- mIsProfileReady = false;
- }
- };
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (profile != BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT) {
+ Log.d(TAG, "The profile is not LE_AUDIO_BROADCAST_ASSISTANT");
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service disconnected");
+ }
+ mProfileManager.callServiceDisconnectedListeners();
+ mIsProfileReady = false;
+ mCachedCallbackExecutorMap.clear();
+ }
+ };
- public LocalBluetoothLeBroadcastAssistant(Context context,
+ public LocalBluetoothLeBroadcastAssistant(
+ Context context,
CachedBluetoothDeviceManager deviceManager,
LocalBluetoothProfileManager profileManager) {
mProfileManager = profileManager;
mDeviceManager = deviceManager;
- BluetoothAdapter.getDefaultAdapter().
- getProfileProxy(context, mServiceListener,
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+ BluetoothAdapter.getDefaultAdapter()
+ .getProfileProxy(
+ context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
mBuilder = new BluetoothLeBroadcastMetadata.Builder();
}
@@ -123,11 +142,11 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
* @param sink Broadcast Sink to which the Broadcast Source should be added
* @param metadata Broadcast Source metadata to be added to the Broadcast Sink
* @param isGroupOp {@code true} if Application wants to perform this operation for all
- * coordinated set members throughout this session. Otherwise, caller
- * would have to add, modify, and remove individual set members.
+ * coordinated set members throughout this session. Otherwise, caller would have to add,
+ * modify, and remove individual set members.
*/
- public void addSource(BluetoothDevice sink, BluetoothLeBroadcastMetadata metadata,
- boolean isGroupOp) {
+ public void addSource(
+ BluetoothDevice sink, BluetoothLeBroadcastMetadata metadata, boolean isGroupOp) {
if (mService == null) {
Log.d(TAG, "The BluetoothLeBroadcastAssistant is null");
return;
@@ -140,36 +159,55 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
* the qr code string.
*
* @param sink Broadcast Sink to which the Broadcast Source should be added
- * @param sourceAddressType hardware MAC Address of the device. See
- * {@link BluetoothDevice.AddressType}.
+ * @param sourceAddressType hardware MAC Address of the device. See {@link
+ * BluetoothDevice.AddressType}.
* @param presentationDelayMicros presentation delay of this Broadcast Source in microseconds.
* @param sourceAdvertisingSid 1-byte long Advertising_SID of the Broadcast Source.
* @param broadcastId 3-byte long Broadcast_ID of the Broadcast Source.
- * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source,
- * {@link BluetoothLeBroadcastMetadata#PA_SYNC_INTERVAL_UNKNOWN} if
- * unknown.
+ * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source, {@link
+ * BluetoothLeBroadcastMetadata#PA_SYNC_INTERVAL_UNKNOWN} if unknown.
* @param isEncrypted whether the Broadcast Source is encrypted.
* @param broadcastCode Broadcast Code for this Broadcast Source, null if code is not required.
* @param sourceDevice source advertiser address.
* @param isGroupOp {@code true} if Application wants to perform this operation for all
- * coordinated set members throughout this session. Otherwise, caller
- * would have to add, modify, and remove individual set members.
+ * coordinated set members throughout this session. Otherwise, caller would have to add,
+ * modify, and remove individual set members.
*/
- public void addSource(@NonNull BluetoothDevice sink, int sourceAddressType,
- int presentationDelayMicros, int sourceAdvertisingSid, int broadcastId,
- int paSyncInterval, boolean isEncrypted, byte[] broadcastCode,
- BluetoothDevice sourceDevice, boolean isGroupOp) {
+ public void addSource(
+ @NonNull BluetoothDevice sink,
+ int sourceAddressType,
+ int presentationDelayMicros,
+ int sourceAdvertisingSid,
+ int broadcastId,
+ int paSyncInterval,
+ boolean isEncrypted,
+ byte[] broadcastCode,
+ BluetoothDevice sourceDevice,
+ boolean isGroupOp) {
if (DEBUG) {
Log.d(TAG, "addSource()");
}
- buildMetadata(sourceAddressType, presentationDelayMicros, sourceAdvertisingSid, broadcastId,
- paSyncInterval, isEncrypted, broadcastCode, sourceDevice);
+ buildMetadata(
+ sourceAddressType,
+ presentationDelayMicros,
+ sourceAdvertisingSid,
+ broadcastId,
+ paSyncInterval,
+ isEncrypted,
+ broadcastCode,
+ sourceDevice);
addSource(sink, mBluetoothLeBroadcastMetadata, isGroupOp);
}
- private void buildMetadata(int sourceAddressType, int presentationDelayMicros,
- int sourceAdvertisingSid, int broadcastId, int paSyncInterval, boolean isEncrypted,
- byte[] broadcastCode, BluetoothDevice sourceDevice) {
+ private void buildMetadata(
+ int sourceAddressType,
+ int presentationDelayMicros,
+ int sourceAdvertisingSid,
+ int broadcastId,
+ int paSyncInterval,
+ boolean isEncrypted,
+ byte[] broadcastCode,
+ BluetoothDevice sourceDevice) {
mBluetoothLeBroadcastMetadata =
mBuilder.setSourceDevice(sourceDevice, sourceAddressType)
.setSourceAdvertisingSid(sourceAdvertisingSid)
@@ -223,10 +261,10 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
/**
* Stops an ongoing search for nearby Broadcast Sources.
*
- * On success, {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopped(int)} will be
- * called with reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}.
- * On failure, {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopFailed(int)} will be
- * called with reason code
+ * <p>On success, {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopped(int)} will be
+ * called with reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST}. On failure,
+ * {@link BluetoothLeBroadcastAssistant.Callback#onSearchStopFailed(int)} will be called with
+ * reason code
*
* @throws IllegalStateException if callback was not registered
*/
@@ -245,8 +283,8 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
* Get information about all Broadcast Sources that a Broadcast Sink knows about.
*
* @param sink Broadcast Sink from which to get all Broadcast Sources
- * @return the list of Broadcast Receive State {@link BluetoothLeBroadcastReceiveState}
- * stored in the Broadcast Sink
+ * @return the list of Broadcast Receive State {@link BluetoothLeBroadcastReceiveState} stored
+ * in the Broadcast Sink
* @throws NullPointerException when <var>sink</var> is null
*/
public @NonNull List<BluetoothLeBroadcastReceiveState> getAllSources(
@@ -261,24 +299,50 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
return mService.getAllSources(sink);
}
- public void registerServiceCallBack(@NonNull @CallbackExecutor Executor executor,
+ /**
+ * Register Broadcast Assistant Callbacks to track its state and receivers
+ *
+ * @param executor Executor object for callback
+ * @param callback Callback object to be registered
+ */
+ public void registerServiceCallBack(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
if (mService == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(
+ TAG,
+ "registerServiceCallBack failed, the BluetoothLeBroadcastAssistant is null.");
+ mCachedCallbackExecutorMap.putIfAbsent(callback, executor);
return;
}
- mService.registerCallback(executor, callback);
+ try {
+ mService.registerCallback(executor, callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "registerServiceCallBack failed. " + e.getMessage());
+ }
}
+ /**
+ * Unregister previously registered Broadcast Assistant Callbacks
+ *
+ * @param callback Callback object to be unregistered
+ */
public void unregisterServiceCallBack(
@NonNull BluetoothLeBroadcastAssistant.Callback callback) {
+ mCachedCallbackExecutorMap.remove(callback);
if (mService == null) {
- Log.d(TAG, "The BluetoothLeBroadcast is null.");
+ Log.d(
+ TAG,
+ "unregisterServiceCallBack failed, the BluetoothLeBroadcastAssistant is null.");
return;
}
- mService.unregisterCallback(callback);
+ try {
+ mService.unregisterCallback(callback);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "unregisterServiceCallBack failed. " + e.getMessage());
+ }
}
public boolean isProfileReady() {
@@ -310,9 +374,11 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
return new ArrayList<BluetoothDevice>(0);
}
return mService.getDevicesMatchingConnectionStates(
- new int[]{BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTING});
+ new int[] {
+ BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING
+ });
}
public boolean isEnabled(BluetoothDevice device) {
@@ -373,9 +439,8 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile
}
if (mService != null) {
try {
- BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT,
- mService);
+ BluetoothAdapter.getDefaultAdapter()
+ .closeProfileProxy(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, mService);
mService = null;
} catch (Throwable t) {
Log.w(TAG, "Error cleaning up LeAudio proxy", t);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 460d9f040e68..ec456e09a3c1 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -106,6 +106,9 @@ public class SecureSettings {
Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
+ // ACCESSIBILITY_QS_TARGETS needs to be restored after ENABLED_ACCESSIBILITY_SERVICES
+ // but before QS_TILES
+ Settings.Secure.ACCESSIBILITY_QS_TARGETS,
Settings.Secure.QS_TILES,
Settings.Secure.QS_AUTO_ADDED_TILES,
Settings.Secure.CONTROLS_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 6c48110ef10b..5ad14ceb31cf 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -320,6 +320,9 @@ public class SecureSettingsValidators {
VALIDATORS.put(
Secure.ACCESSIBILITY_BUTTON_TARGETS,
ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
+ VALIDATORS.put(
+ Secure.ACCESSIBILITY_QS_TARGETS,
+ ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ONE_HANDED_MODE_ACTIVATED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ONE_HANDED_MODE_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a97888949446..5afcd5db1b5f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1813,6 +1813,9 @@ class SettingsProtoDumpUtil {
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
SecureSettingsProto.Accessibility.BUTTON_TARGETS);
dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_QS_TARGETS,
+ SecureSettingsProto.Accessibility.QS_TARGETS);
+ dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
SecureSettingsProto.Accessibility.ACCESSIBILITY_MAGNIFICATION_CAPABILITY);
dumpSetting(s, p,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d12d9d665a8c..bacab0f8f1e8 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -879,6 +879,9 @@
<uses-permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE" />
+ <!-- Permissions required for CTS test - CtsAccessibilityServiceTestCases-->
+ <uses-permission android:name="android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING" />
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 7061e2cb8a4e..f10ac1bf1e0a 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -204,6 +204,7 @@ android_library {
"lottie",
"LowLightDreamLib",
"motion_tool_lib",
+ "notification_flags_lib",
],
libs: [
"keepanno-annotations",
@@ -328,6 +329,7 @@ android_library {
"androidx.compose.ui_ui",
"flag-junit",
"platform-test-annotations",
+ "notification_flags_lib",
],
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a26b311b1f8f..facb244a5489 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -61,6 +61,13 @@ flag {
}
flag {
+ name: "refactor_get_current_user"
+ namespace: "systemui"
+ description: "KeyguardUpdateMonitor.getCurrentUser() was providing outdated results."
+ bug: "305984787"
+}
+
+flag {
name: "notification_throttle_hun"
namespace: "systemui"
description: "During notification avalanche, throttle HUNs showing in fast succession."
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index f7d9056c33dc..9c46ebdc5ac8 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -21,7 +21,6 @@ import android.app.ActivityTaskManager
import android.app.PendingIntent
import android.app.TaskInfo
import android.graphics.Matrix
-import android.graphics.Path
import android.graphics.Rect
import android.graphics.RectF
import android.os.Build
@@ -37,7 +36,6 @@ import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
-import android.view.animation.Interpolator
import android.view.animation.PathInterpolator
import androidx.annotation.AnyThread
import androidx.annotation.BinderThread
@@ -93,7 +91,7 @@ class ActivityLaunchAnimator(
val INTERPOLATORS =
LaunchAnimator.Interpolators(
positionInterpolator = Interpolators.EMPHASIZED,
- positionXInterpolator = createPositionXInterpolator(),
+ positionXInterpolator = Interpolators.EMPHASIZED_COMPLEMENT,
contentBeforeFadeOutInterpolator = Interpolators.LINEAR_OUT_SLOW_IN,
contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f)
)
@@ -121,16 +119,6 @@ class ActivityLaunchAnimator(
* cancelled by WM.
*/
private const val LONG_LAUNCH_TIMEOUT = 5_000L
-
- private fun createPositionXInterpolator(): Interpolator {
- val path =
- Path().apply {
- moveTo(0f, 0f)
- cubicTo(0.1217f, 0.0462f, 0.15f, 0.4686f, 0.1667f, 0.66f)
- cubicTo(0.1834f, 0.8878f, 0.1667f, 1f, 1f, 1f)
- }
- return PathInterpolator(path)
- }
}
/**
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
index 914e5f2c17bf..fd04b5ee0d9c 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -51,6 +51,7 @@ object ComposeFacade : BaseComposeFacade {
activity: ComponentActivity,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
) {
throwComposeUnavailableError()
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
index 59bd95bd9027..5055ee1d73f6 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -66,12 +66,14 @@ object ComposeFacade : BaseComposeFacade {
activity: ComponentActivity,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
) {
activity.setContent {
PlatformTheme {
CommunalHub(
viewModel = viewModel,
onOpenWidgetPicker = onOpenWidgetPicker,
+ onEditDone = onEditDone,
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index 47f5663f25a7..1d7c7d636158 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -33,7 +33,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
@@ -311,15 +310,21 @@ private fun BesideUserSwitcherLayout(
Row(
modifier =
- modifier.pointerInput(Unit) {
- detectTapGestures(
- onDoubleTap = { offset ->
- // Depending on where the user double tapped, switch the elements such that
- // the endContent is closer to the side that was double tapped.
- setSwapped(offset.x < size.width / 2)
- }
- )
- },
+ modifier
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onDoubleTap = { offset ->
+ // Depending on where the user double tapped, switch the elements such
+ // that the non-swapped element is closer to the side that was double
+ // tapped.
+ setSwapped(offset.x < size.width / 2)
+ }
+ )
+ }
+ .padding(
+ top = if (isHeightExpanded) 128.dp else 96.dp,
+ bottom = if (isHeightExpanded) 128.dp else 48.dp,
+ ),
) {
val animatedOffset by
animateFloatAsState(
@@ -359,20 +364,11 @@ private fun BesideUserSwitcherLayout(
UserSwitcher(
viewModel = viewModel,
- modifier = Modifier.weight(1f).align(Alignment.CenterVertically).swappable(),
+ modifier = Modifier.weight(1f).swappable(),
)
FoldAware(
- modifier =
- Modifier.weight(1f)
- .padding(
- if (isHeightExpanded) {
- PaddingValues(vertical = 128.dp)
- } else {
- PaddingValues(top = 94.dp, bottom = 48.dp)
- }
- )
- .swappable(inversed = true),
+ modifier = Modifier.weight(1f).swappable(inversed = true),
viewModel = viewModel,
aboveFold = {
Column(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 185a06c70f9e..d83f3aae1ace 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -14,6 +14,7 @@ import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -28,15 +29,20 @@ import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.FixedSizeEdgeDetector
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.SceneTransitionLayoutState
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.transform
object Communal {
@@ -60,7 +66,7 @@ val sceneTransitions = transitions {
* This is a temporary container to allow the communal UI to use [SceneTransitionLayout] for gesture
* handling and transitions before the full Flexiglass layout is ready.
*/
-@OptIn(ExperimentalComposeUiApi::class)
+@OptIn(ExperimentalComposeUiApi::class, ExperimentalCoroutinesApi::class)
@Composable
fun CommunalContainer(
modifier: Modifier = Modifier,
@@ -81,6 +87,15 @@ fun CommunalContainer(
return
}
+ // This effect exposes the SceneTransitionLayout's observable transition state to the rest of
+ // the system, and unsets it when the view is disposed to avoid a memory leak.
+ DisposableEffect(viewModel, sceneTransitionLayoutState) {
+ viewModel.setTransitionState(
+ sceneTransitionLayoutState.observableTransitionState().map { it.toModel() }
+ )
+ onDispose { viewModel.setTransitionState(null) }
+ }
+
Box(modifier = modifier.fillMaxSize()) {
SceneTransitionLayout(
modifier = Modifier.fillMaxSize(),
@@ -171,18 +186,40 @@ private fun SceneScope.CommunalScene(
Box(modifier.element(Communal.Elements.Content)) { CommunalHub(viewModel = viewModel) }
}
-// TODO(b/293899074): Remove these conversions once Compose can be used throughout SysUI.
+// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
object TransitionSceneKey {
val Blank = CommunalSceneKey.Blank.toTransitionSceneKey()
val Communal = CommunalSceneKey.Communal.toTransitionSceneKey()
}
+// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
+fun SceneKey.toCommunalSceneKey(): CommunalSceneKey {
+ return this.identity as CommunalSceneKey
+}
+
+// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
fun CommunalSceneKey.toTransitionSceneKey(): SceneKey {
return SceneKey(name = toString(), identity = this)
}
-fun SceneKey.toCommunalSceneKey(): CommunalSceneKey {
- return this.identity as CommunalSceneKey
+/**
+ * Converts between the [SceneTransitionLayout] state class and our forked data class that can be
+ * used throughout SysUI.
+ */
+// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
+fun ObservableTransitionState.toModel(): ObservableCommunalTransitionState {
+ return when (this) {
+ is ObservableTransitionState.Idle ->
+ ObservableCommunalTransitionState.Idle(scene.toCommunalSceneKey())
+ is ObservableTransitionState.Transition ->
+ ObservableCommunalTransitionState.Transition(
+ fromScene = fromScene.toCommunalSceneKey(),
+ toScene = toScene.toCommunalSceneKey(),
+ progress = progress,
+ isInitiatedByUserInput = isInitiatedByUserInput,
+ isUserInputOngoing = isUserInputOngoing,
+ )
+ }
}
object ContainerDimensions {
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 e8ecd3a66186..2a9cf0fdc507 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,10 +25,12 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
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
@@ -36,23 +38,41 @@ import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
+import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.layout.positionInWindow
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
@@ -66,21 +86,38 @@ fun CommunalHub(
modifier: Modifier = Modifier,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: (() -> Unit)? = null,
+ onEditDone: (() -> Unit)? = null,
) {
val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
+ var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
+ var toolbarSize: IntSize? by remember { mutableStateOf(null) }
+ var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
+ var isDraggingToRemove by remember { mutableStateOf(false) }
+
Box(
modifier = modifier.fillMaxSize().background(Color.White),
) {
CommunalHubLazyGrid(
- modifier = Modifier.height(Dimensions.GridHeight).align(Alignment.CenterStart),
+ modifier = Modifier.align(Alignment.CenterStart),
communalContent = communalContent,
- isEditMode = viewModel.isEditMode,
viewModel = viewModel,
- )
- if (viewModel.isEditMode && onOpenWidgetPicker != null) {
- IconButton(onClick = onOpenWidgetPicker) {
- Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
+ contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize),
+ setGridCoordinates = { gridCoordinates = it },
+ updateDragPositionForRemove = {
+ isDraggingToRemove =
+ checkForDraggingToRemove(it, removeButtonCoordinates, gridCoordinates)
+ isDraggingToRemove
}
+ )
+
+ if (viewModel.isEditMode && onOpenWidgetPicker != null && onEditDone != null) {
+ Toolbar(
+ isDraggingToRemove = isDraggingToRemove,
+ setToolbarSize = { toolbarSize = it },
+ setRemoveButtonCoordinates = { removeButtonCoordinates = it },
+ onEditDone = onEditDone,
+ onOpenWidgetPicker = onOpenWidgetPicker,
+ )
} else {
IconButton(onClick = viewModel::onOpenWidgetEditor) {
Icon(Icons.Default.Edit, stringResource(R.string.button_to_open_widget_editor))
@@ -103,25 +140,38 @@ fun CommunalHub(
@Composable
private fun CommunalHubLazyGrid(
communalContent: List<CommunalContentModel>,
- isEditMode: Boolean,
viewModel: BaseCommunalViewModel,
modifier: Modifier = Modifier,
+ contentPadding: PaddingValues,
+ setGridCoordinates: (coordinates: LayoutCoordinates) -> Unit,
+ updateDragPositionForRemove: (offset: Offset) -> Boolean,
) {
var gridModifier = modifier
val gridState = rememberLazyGridState()
var list = communalContent
var dragDropState: GridDragDropState? = null
- if (isEditMode && viewModel is CommunalEditModeViewModel) {
+ if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
val contentListState = rememberContentListState(communalContent, viewModel)
list = contentListState.list
- dragDropState = rememberGridDragDropState(gridState, contentListState)
- gridModifier = gridModifier.dragContainer(dragDropState)
+ dragDropState =
+ rememberGridDragDropState(
+ gridState = gridState,
+ contentListState = contentListState,
+ updateDragPositionForRemove = updateDragPositionForRemove
+ )
+ gridModifier =
+ gridModifier
+ .fillMaxSize()
+ .dragContainer(dragDropState, beforeContentPadding(contentPadding))
+ .onGloballyPositioned { setGridCoordinates(it) }
+ } else {
+ gridModifier = gridModifier.height(Dimensions.GridHeight)
}
LazyHorizontalGrid(
modifier = gridModifier,
state = gridState,
rows = GridCells.Fixed(CommunalContentSize.FULL.span),
- contentPadding = PaddingValues(horizontal = Dimensions.Spacing),
+ contentPadding = contentPadding,
horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
) {
@@ -130,19 +180,18 @@ private fun CommunalHubLazyGrid(
key = { index -> list[index].key },
span = { index -> GridItemSpan(list[index].size.span) },
) { index ->
- val cardModifier = Modifier.fillMaxHeight().width(Dimensions.CardWidth)
+ val cardModifier = Modifier.width(Dimensions.CardWidth)
val size =
SizeF(
Dimensions.CardWidth.value,
list[index].size.dp().value,
)
- if (isEditMode && dragDropState != null) {
+ if (viewModel.isEditMode && dragDropState != null) {
DraggableItem(dragDropState = dragDropState, enabled = true, index = index) {
isDragging ->
val elevation by animateDpAsState(if (isDragging) 4.dp else 1.dp)
CommunalContent(
modifier = cardModifier,
- deleteOnClick = viewModel::onDeleteWidget,
elevation = elevation,
model = list[index],
viewModel = viewModel,
@@ -161,6 +210,95 @@ private fun CommunalHubLazyGrid(
}
}
+/**
+ * Toolbar that contains action buttons to
+ * 1) open the widget picker
+ * 2) remove a widget from the grid and
+ * 3) exit the edit mode.
+ */
+@Composable
+private fun Toolbar(
+ isDraggingToRemove: Boolean,
+ setToolbarSize: (toolbarSize: IntSize) -> Unit,
+ setRemoveButtonCoordinates: (coordinates: LayoutCoordinates) -> Unit,
+ onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
+) {
+ Row(
+ modifier =
+ Modifier.fillMaxWidth()
+ .padding(
+ top = Dimensions.ToolbarPaddingTop,
+ start = Dimensions.ToolbarPaddingHorizontal,
+ end = Dimensions.ToolbarPaddingHorizontal,
+ )
+ .onSizeChanged { setToolbarSize(it) },
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ val buttonContentPadding =
+ PaddingValues(
+ vertical = Dimensions.ToolbarButtonPaddingVertical,
+ horizontal = Dimensions.ToolbarButtonPaddingHorizontal,
+ )
+ val spacerModifier = Modifier.width(Dimensions.ToolbarButtonSpaceBetween)
+ Button(
+ onClick = onOpenWidgetPicker,
+ colors = filledSecondaryButtonColors(),
+ contentPadding = buttonContentPadding
+ ) {
+ Icon(Icons.Default.Add, stringResource(R.string.button_to_open_widget_editor))
+ Spacer(spacerModifier)
+ Text(
+ text = stringResource(R.string.hub_mode_add_widget_button_text),
+ )
+ }
+
+ val buttonColors =
+ if (isDraggingToRemove) filledButtonColors() else ButtonDefaults.outlinedButtonColors()
+ OutlinedButton(
+ onClick = {},
+ colors = buttonColors,
+ contentPadding = buttonContentPadding,
+ modifier = Modifier.onGloballyPositioned { setRemoveButtonCoordinates(it) },
+ ) {
+ Icon(Icons.Outlined.Delete, stringResource(R.string.button_to_open_widget_editor))
+ Spacer(spacerModifier)
+ Text(
+ text = stringResource(R.string.button_to_remove_widget),
+ )
+ }
+
+ Button(
+ onClick = onEditDone,
+ colors = filledButtonColors(),
+ contentPadding = buttonContentPadding
+ ) {
+ Text(
+ text = stringResource(R.string.hub_mode_editing_exit_button_text),
+ )
+ }
+ }
+}
+
+@Composable
+private fun filledButtonColors(): ButtonColors {
+ val colors = LocalAndroidColorScheme.current
+ return ButtonDefaults.buttonColors(
+ containerColor = colors.primary,
+ contentColor = colors.onPrimary,
+ )
+}
+
+@Composable
+private fun filledSecondaryButtonColors(): ButtonColors {
+ val colors = LocalAndroidColorScheme.current
+ return ButtonDefaults.buttonColors(
+ containerColor = colors.secondary,
+ contentColor = colors.onSecondary,
+ )
+}
+
@Composable
private fun CommunalContent(
model: CommunalContentModel,
@@ -168,11 +306,9 @@ private fun CommunalContent(
size: SizeF,
modifier: Modifier = Modifier,
elevation: Dp = 0.dp,
- deleteOnClick: ((id: Int) -> Unit)? = null,
) {
when (model) {
- is CommunalContentModel.Widget ->
- WidgetContent(model, size, elevation, deleteOnClick, modifier)
+ is CommunalContentModel.Widget -> WidgetContent(model, size, elevation, modifier)
is CommunalContentModel.Smartspace -> SmartspaceContent(model, modifier)
is CommunalContentModel.Tutorial -> TutorialContent(modifier)
is CommunalContentModel.Umo -> Umo(viewModel, modifier)
@@ -184,19 +320,12 @@ private fun WidgetContent(
model: CommunalContentModel.Widget,
size: SizeF,
elevation: Dp,
- deleteOnClick: ((id: Int) -> Unit)?,
modifier: Modifier = Modifier,
) {
- // TODO(b/309009246): update background color
Card(
- modifier = modifier.fillMaxSize().background(Color.White),
+ modifier = modifier.height(size.height.dp),
elevation = CardDefaults.cardElevation(draggedElevation = elevation),
) {
- if (deleteOnClick != null) {
- IconButton(onClick = { deleteOnClick(model.appWidgetId) }) {
- Icon(Icons.Default.Close, stringResource(R.string.button_to_remove_widget))
- }
- }
AndroidView(
modifier = modifier,
factory = { context ->
@@ -249,6 +378,60 @@ private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier)
)
}
+/**
+ * Returns the `contentPadding` of the grid. Use the vertical padding to push the grid content area
+ * below the toolbar and let the grid take the max size. This ensures the item can be dragged
+ * outside the grid over the toolbar, without part of it getting clipped by the container.
+ */
+@Composable
+private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues {
+ if (!isEditMode || toolbarSize == null) {
+ return PaddingValues(horizontal = Dimensions.Spacing)
+ }
+ val configuration = LocalConfiguration.current
+ val density = LocalDensity.current
+ val screenHeight = configuration.screenHeightDp.dp
+ val toolbarHeight = with(density) { Dimensions.ToolbarPaddingTop + toolbarSize.height.toDp() }
+ val verticalPadding =
+ ((screenHeight - toolbarHeight - Dimensions.GridHeight) / 2).coerceAtLeast(
+ Dimensions.Spacing
+ )
+ return PaddingValues(
+ start = Dimensions.ToolbarPaddingHorizontal,
+ end = Dimensions.ToolbarPaddingHorizontal,
+ top = verticalPadding + toolbarHeight,
+ bottom = verticalPadding
+ )
+}
+
+@Composable
+private fun beforeContentPadding(paddingValues: PaddingValues): ContentPaddingInPx {
+ return with(LocalDensity.current) {
+ ContentPaddingInPx(
+ startPadding = paddingValues.calculateLeftPadding(LayoutDirection.Ltr).toPx(),
+ topPadding = paddingValues.calculateTopPadding().toPx()
+ )
+ }
+}
+
+/**
+ * Check whether the pointer position that the item is being dragged at is within the coordinates of
+ * the remove button in the toolbar. Returns true if the item is removable.
+ */
+private fun checkForDraggingToRemove(
+ offset: Offset,
+ removeButtonCoordinates: LayoutCoordinates?,
+ gridCoordinates: LayoutCoordinates?,
+): Boolean {
+ if (removeButtonCoordinates == null || gridCoordinates == null) {
+ return false
+ }
+ val pointer = gridCoordinates.positionInWindow() + offset
+ val removeButton = removeButtonCoordinates.positionInWindow()
+ return pointer.x in removeButton.x..removeButton.x + removeButtonCoordinates.size.width &&
+ pointer.y in removeButton.y..removeButton.y + removeButtonCoordinates.size.height
+}
+
private fun CommunalContentSize.dp(): Dp {
return when (this) {
CommunalContentSize.FULL -> Dimensions.CardHeightFull
@@ -257,6 +440,8 @@ private fun CommunalContentSize.dp(): Dp {
}
}
+data class ContentPaddingInPx(val startPadding: Float, val topPadding: Float)
+
object Dimensions {
val CardWidth = 464.dp
val CardHeightFull = 630.dp
@@ -264,4 +449,11 @@ object Dimensions {
val CardHeightThird = 199.dp
val GridHeight = CardHeightFull
val Spacing = 16.dp
+
+ // The sizing/padding of the toolbar in glanceable hub edit mode
+ val ToolbarPaddingTop = 27.dp
+ val ToolbarPaddingHorizontal = 16.dp
+ val ToolbarButtonPaddingHorizontal = 24.dp
+ val ToolbarButtonPaddingVertical = 16.dp
+ val ToolbarButtonSpaceBetween = 8.dp
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 6cfa2f233f46..5451d0550095 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -48,12 +48,18 @@ import kotlinx.coroutines.launch
@Composable
fun rememberGridDragDropState(
gridState: LazyGridState,
- contentListState: ContentListState
+ contentListState: ContentListState,
+ updateDragPositionForRemove: (offset: Offset) -> Boolean,
): GridDragDropState {
val scope = rememberCoroutineScope()
val state =
remember(gridState, contentListState) {
- GridDragDropState(state = gridState, contentListState = contentListState, scope = scope)
+ GridDragDropState(
+ state = gridState,
+ contentListState = contentListState,
+ scope = scope,
+ updateDragPositionForRemove = updateDragPositionForRemove
+ )
}
LaunchedEffect(state) {
while (true) {
@@ -67,23 +73,30 @@ fun rememberGridDragDropState(
/**
* Handles drag and drop cards in the glanceable hub. While dragging to move, other items that are
* affected will dynamically get positioned and the state is tracked by [ContentListState]. When
- * dragging to remove, affected cards will be moved and [ContentListState.onRemove] is called to
- * remove the dragged item. On dragging ends, call [ContentListState.onSaveList] to persist the
- * change.
+ * dragging to remove, affected cards will be moved and [updateDragPositionForRemove] is called to
+ * check whether the dragged item can be removed. On dragging ends, call [ContentListState.onRemove]
+ * to remove the dragged item if condition met and call [ContentListState.onSaveList] to persist any
+ * change in ordering.
*/
class GridDragDropState
internal constructor(
private val state: LazyGridState,
private val contentListState: ContentListState,
private val scope: CoroutineScope,
+ private val updateDragPositionForRemove: (offset: Offset) -> Boolean
) {
var draggingItemIndex by mutableStateOf<Int?>(null)
private set
+ var isDraggingToRemove by mutableStateOf(false)
+ private set
+
internal val scrollChannel = Channel<Float>()
private var draggingItemDraggedDelta by mutableStateOf(Offset.Zero)
private var draggingItemInitialOffset by mutableStateOf(Offset.Zero)
+ private var dragStartPointerOffset by mutableStateOf(Offset.Zero)
+
internal val draggingItemOffset: Offset
get() =
draggingItemLayoutInfo?.let { item ->
@@ -94,27 +107,36 @@ internal constructor(
private val draggingItemLayoutInfo: LazyGridItemInfo?
get() = state.layoutInfo.visibleItemsInfo.firstOrNull { it.index == draggingItemIndex }
- internal fun onDragStart(offset: Offset) {
+ internal fun onDragStart(offset: Offset, contentOffset: Offset) {
state.layoutInfo.visibleItemsInfo
.firstOrNull { item ->
+ // grid item offset is based off grid content container so we need to deduct
+ // before content padding from the initial pointer position
item.isEditable &&
- offset.x.toInt() in item.offset.x..item.offsetEnd.x &&
- offset.y.toInt() in item.offset.y..item.offsetEnd.y
+ (offset.x - contentOffset.x).toInt() in item.offset.x..item.offsetEnd.x &&
+ (offset.y - contentOffset.y).toInt() in item.offset.y..item.offsetEnd.y
}
?.apply {
+ dragStartPointerOffset = offset - this.offset.toOffset()
draggingItemIndex = index
draggingItemInitialOffset = this.offset.toOffset()
}
}
internal fun onDragInterrupted() {
- if (draggingItemIndex != null) {
+ draggingItemIndex?.let {
+ if (isDraggingToRemove) {
+ contentListState.onRemove(it)
+ isDraggingToRemove = false
+ updateDragPositionForRemove(Offset.Zero)
+ }
// persist list editing changes on dragging ends
contentListState.onSaveList()
draggingItemIndex = null
}
draggingItemDraggedDelta = Offset.Zero
draggingItemInitialOffset = Offset.Zero
+ dragStartPointerOffset = Offset.Zero
}
internal fun onDrag(offset: Offset) {
@@ -152,18 +174,13 @@ internal constructor(
contentListState.onMove(draggingItem.index, targetItem.index)
}
draggingItemIndex = targetItem.index
+ isDraggingToRemove = false
} else {
val overscroll = checkForOverscroll(startOffset, endOffset)
if (overscroll != 0f) {
scrollChannel.trySend(overscroll)
}
- val removeOffset = checkForRemove(startOffset)
- if (removeOffset != 0f) {
- draggingItemIndex?.let {
- contentListState.onRemove(it)
- draggingItemIndex = null
- }
- }
+ isDraggingToRemove = checkForRemove(startOffset)
}
}
@@ -185,14 +202,11 @@ internal constructor(
}
}
- // TODO(b/309968801): a temporary solution to decide whether to remove card when it's dragged up
- // and out of grid. Once we have a taskbar, calculate the intersection of the dragged item with
- // the Remove button.
- private fun checkForRemove(startOffset: Offset): Float {
+ /** Calls the callback with the updated drag position and returns whether to remove the item. */
+ private fun checkForRemove(startOffset: Offset): Boolean {
return if (draggingItemDraggedDelta.y < 0)
- (startOffset.y + Dimensions.CardHeightHalf.value - state.layoutInfo.viewportStartOffset)
- .coerceAtMost(0f)
- else 0f
+ updateDragPositionForRemove(startOffset + dragStartPointerOffset)
+ else false
}
}
@@ -204,14 +218,22 @@ private operator fun Offset.plus(size: Size): Offset {
return Offset(x + size.width, y + size.height)
}
-fun Modifier.dragContainer(dragDropState: GridDragDropState): Modifier {
- return pointerInput(dragDropState) {
+fun Modifier.dragContainer(
+ dragDropState: GridDragDropState,
+ beforeContentPadding: ContentPaddingInPx
+): Modifier {
+ return pointerInput(dragDropState, beforeContentPadding) {
detectDragGesturesAfterLongPress(
onDrag = { change, offset ->
change.consume()
dragDropState.onDrag(offset = offset)
},
- onDragStart = { offset -> dragDropState.onDragStart(offset) },
+ onDragStart = { offset ->
+ dragDropState.onDragStart(
+ offset,
+ Offset(beforeContentPadding.startPadding, beforeContentPadding.topPadding)
+ )
+ },
onDragEnd = { dragDropState.onDragInterrupted() },
onDragCancel = { dragDropState.onDragInterrupted() }
)
@@ -237,6 +259,7 @@ fun LazyGridItemScope.DraggableItem(
Modifier.zIndex(1f).graphicsLayer {
translationX = dragDropState.draggingItemOffset.x
translationY = dragDropState.draggingItemOffset.y
+ alpha = if (dragDropState.isDraggingToRemove) 0.5f else 1f
}
} else {
Modifier.animateItemPlacement()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index 009f8bb38e61..2944bd9f9a8e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -174,12 +174,8 @@ private fun <T> computeValue(
lerp: (T, T, Float) -> T,
canOverflow: Boolean,
): T {
- val state = layoutImpl.state.transitionState
- if (
- state !is TransitionState.Transition ||
- state.fromScene == state.toScene ||
- !layoutImpl.isTransitionReady(state)
- ) {
+ val transition = layoutImpl.state.currentTransition
+ if (transition == null || !layoutImpl.isTransitionReady(transition)) {
return sharedValue.value
}
@@ -195,10 +191,11 @@ private fun <T> computeValue(
return value as Element.SharedValue<T>
}
- val fromValue = sceneValue(state.fromScene)
- val toValue = sceneValue(state.toScene)
+ val fromValue = sceneValue(transition.fromScene)
+ val toValue = sceneValue(transition.toScene)
return if (fromValue != null && toValue != null) {
- val progress = if (canOverflow) state.progress else state.progress.coerceIn(0f, 1f)
+ val progress =
+ if (canOverflow) transition.progress else transition.progress.coerceIn(0f, 1f)
lerp(fromValue.value, toValue.value, progress)
} else if (fromValue != null) {
fromValue.value
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 199832bc4ab6..ba6d00e3b7f5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -28,11 +28,11 @@ import kotlinx.coroutines.launch
* the currently running transition, if there is one.
*/
internal fun CoroutineScope.animateToScene(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
target: SceneKey,
) {
- val state = layoutImpl.state.transitionState
- if (state.currentScene == target) {
+ val transitionState = layoutState.transitionState
+ if (transitionState.currentScene == target) {
// This can happen in 3 different situations, for which there isn't anything else to do:
// 1. There is no ongoing transition and [target] is already the current scene.
// 2. The user is swiping to [target] from another scene and released their pointer such
@@ -44,50 +44,47 @@ internal fun CoroutineScope.animateToScene(
return
}
- when (state) {
- is TransitionState.Idle -> animate(layoutImpl, target)
+ when (transitionState) {
+ is TransitionState.Idle -> animate(layoutState, target)
is TransitionState.Transition -> {
- if (state.toScene == state.fromScene) {
- // Same as idle.
- animate(layoutImpl, target)
- return
- }
-
// A transition is currently running: first check whether `transition.toScene` or
// `transition.fromScene` is the same as our target scene, in which case the transition
// can be accelerated or reversed to end up in the target state.
- if (state.toScene == target) {
+ if (transitionState.toScene == target) {
// The user is currently swiping to [target] but didn't release their pointer yet:
// animate the progress to `1`.
- check(state.fromScene == state.currentScene)
- val progress = state.progress
+ check(transitionState.fromScene == transitionState.currentScene)
+ val progress = transitionState.progress
if ((1f - progress).absoluteValue < ProgressVisibilityThreshold) {
- // The transition is already finished (progress ~= 1): no need to animate.
- layoutImpl.state.transitionState = TransitionState.Idle(state.currentScene)
+ // The transition is already finished (progress ~= 1): no need to animate. We
+ // finish the current transition early to make sure that the current state
+ // change is committed.
+ layoutState.finishTransition(transitionState, transitionState.currentScene)
} else {
// The transition is in progress: start the canned animation at the same
// progress as it was in.
// TODO(b/290184746): Also take the current velocity into account.
- animate(layoutImpl, target, startProgress = progress)
+ animate(layoutState, target, startProgress = progress)
}
return
}
- if (state.fromScene == target) {
+ if (transitionState.fromScene == target) {
// There is a transition from [target] to another scene: simply animate the same
// transition progress to `0`.
- check(state.toScene == state.currentScene)
- val progress = state.progress
+ check(transitionState.toScene == transitionState.currentScene)
+ val progress = transitionState.progress
if (progress.absoluteValue < ProgressVisibilityThreshold) {
- // The transition is at progress ~= 0: no need to animate.
- layoutImpl.state.transitionState = TransitionState.Idle(state.currentScene)
+ // The transition is at progress ~= 0: no need to animate.We finish the current
+ // transition early to make sure that the current state change is committed.
+ layoutState.finishTransition(transitionState, transitionState.currentScene)
} else {
// TODO(b/290184746): Also take the current velocity into account.
- animate(layoutImpl, target, startProgress = progress, reversed = true)
+ animate(layoutState, target, startProgress = progress, reversed = true)
}
return
@@ -95,27 +92,22 @@ internal fun CoroutineScope.animateToScene(
// Generic interruption; the current transition is neither from or to [target].
// TODO(b/290930950): Better handle interruptions here.
- animate(layoutImpl, target)
+ animate(layoutState, target)
}
}
}
private fun CoroutineScope.animate(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
target: SceneKey,
startProgress: Float = 0f,
reversed: Boolean = false,
) {
- val fromScene = layoutImpl.state.transitionState.currentScene
+ val fromScene = layoutState.transitionState.currentScene
val isUserInput =
- (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
+ (layoutState.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
?: false
- val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec
- val visibilityThreshold =
- (animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
- val animatable = Animatable(startProgress, visibilityThreshold = visibilityThreshold)
-
val targetProgress = if (reversed) 0f else 1f
val transition =
if (reversed) {
@@ -125,7 +117,6 @@ private fun CoroutineScope.animate(
currentScene = target,
isInitiatedByUserInput = isUserInput,
isUserInputOngoing = false,
- animatable = animatable,
)
} else {
OneOffTransition(
@@ -134,32 +125,46 @@ private fun CoroutineScope.animate(
currentScene = target,
isInitiatedByUserInput = isUserInput,
isUserInputOngoing = false,
- animatable = animatable,
)
}
- // Change the current layout state to use this new transition.
- layoutImpl.state.transitionState = transition
+ // Change the current layout state to start this new transition. This will compute the
+ // TransformationSpec associated to this transition, which we need to initialize the Animatable
+ // that will actually animate it.
+ layoutState.startTransition(transition)
+
+ // The transformation now contains the spec that we should use to instantiate the Animatable.
+ val animationSpec = layoutState.transformationSpec.progressSpec
+ val visibilityThreshold =
+ (animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
+ val animatable =
+ Animatable(startProgress, visibilityThreshold = visibilityThreshold).also {
+ transition.animatable = it
+ }
// Animate the progress to its target value.
launch {
animatable.animateTo(targetProgress, animationSpec)
-
- // Unless some other external state change happened, the state should now be idle.
- if (layoutImpl.state.transitionState == transition) {
- layoutImpl.state.transitionState = TransitionState.Idle(target)
- }
+ layoutState.finishTransition(transition, target)
}
}
private class OneOffTransition(
- override val fromScene: SceneKey,
- override val toScene: SceneKey,
+ fromScene: SceneKey,
+ toScene: SceneKey,
override val currentScene: SceneKey,
override val isInitiatedByUserInput: Boolean,
override val isUserInputOngoing: Boolean,
- private val animatable: Animatable<Float, AnimationVector1D>,
-) : TransitionState.Transition {
+) : TransitionState.Transition(fromScene, toScene) {
+ /**
+ * The animatable used to animate this transition.
+ *
+ * Note: This is lateinit because we need to first create this Transition object so that
+ * [SceneTransitionLayoutState] can compute the transformations and animation spec associated to
+ * it, which is need to initialize this Animatable.
+ */
+ lateinit var animatable: Animatable<Float, AnimationVector1D>
+
override val progress: Float
get() = animatable.value
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 31604a6817f0..5dc1079e8b56 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -181,15 +181,11 @@ private data class ElementModifier(
}
internal class ElementNode(
- layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
- element: Element,
- sceneValues: Element.TargetValues,
+ private var layoutImpl: SceneTransitionLayoutImpl,
+ private var scene: Scene,
+ private var element: Element,
+ private var sceneValues: Element.TargetValues,
) : Modifier.Node(), DrawModifierNode {
- private var layoutImpl: SceneTransitionLayoutImpl = layoutImpl
- private var scene: Scene = scene
- private var element: Element = element
- private var sceneValues: Element.TargetValues = sceneValues
override fun onAttach() {
super.onAttach()
@@ -283,27 +279,27 @@ private fun shouldDrawElement(
scene: Scene,
element: Element,
): Boolean {
- val state = layoutImpl.state.transitionState
+ val transition = layoutImpl.state.currentTransition
// Always draw the element if there is no ongoing transition or if the element is not shared.
if (
- state !is TransitionState.Transition ||
- state.fromScene == state.toScene ||
- !layoutImpl.isTransitionReady(state) ||
- state.fromScene !in element.sceneValues ||
- state.toScene !in element.sceneValues
+ transition == null ||
+ !layoutImpl.isTransitionReady(transition) ||
+ transition.fromScene !in element.sceneValues ||
+ transition.toScene !in element.sceneValues
) {
return true
}
- val sharedTransformation = sharedElementTransformation(layoutImpl, state, element.key)
+ val sharedTransformation =
+ sharedElementTransformation(layoutImpl.state, transition, element.key)
if (sharedTransformation?.enabled == false) {
return true
}
return shouldDrawOrComposeSharedElement(
layoutImpl,
- state,
+ transition,
scene.key,
element.key,
sharedTransformation,
@@ -332,21 +328,21 @@ internal fun shouldDrawOrComposeSharedElement(
}
private fun isSharedElementEnabled(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
transition: TransitionState.Transition,
element: ElementKey,
): Boolean {
- return sharedElementTransformation(layoutImpl, transition, element)?.enabled ?: true
+ return sharedElementTransformation(layoutState, transition, element)?.enabled ?: true
}
internal fun sharedElementTransformation(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
transition: TransitionState.Transition,
element: ElementKey,
): SharedElementTransformation? {
- val spec = layoutImpl.transitions.transitionSpec(transition.fromScene, transition.toScene)
- val sharedInFromScene = spec.transformations(element, transition.fromScene).shared
- val sharedInToScene = spec.transformations(element, transition.toScene).shared
+ val transformationSpec = layoutState.transformationSpec
+ val sharedInFromScene = transformationSpec.transformations(element, transition.fromScene).shared
+ val sharedInToScene = transformationSpec.transformations(element, transition.toScene).shared
// The sharedElement() transformation must either be null or be the same in both scenes.
if (sharedInFromScene != sharedInToScene) {
@@ -372,13 +368,9 @@ private fun isElementOpaque(
scene: Scene,
sceneValues: Element.TargetValues,
): Boolean {
- val state = layoutImpl.state.transitionState
-
- if (state !is TransitionState.Transition || state.fromScene == state.toScene) {
- return true
- }
+ val transition = layoutImpl.state.currentTransition ?: return true
- if (!layoutImpl.isTransitionReady(state)) {
+ if (!layoutImpl.isTransitionReady(transition)) {
val lastValue =
sceneValues.lastValues.alpha.takeIf { it != Element.AlphaUnspecified }
?: element.lastSharedValues.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f
@@ -386,8 +378,8 @@ private fun isElementOpaque(
return lastValue == 1f
}
- val fromScene = state.fromScene
- val toScene = state.toScene
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromValues = element.sceneValues[fromScene]
val toValues = element.sceneValues[toScene]
@@ -396,14 +388,11 @@ private fun isElementOpaque(
}
val isSharedElement = fromValues != null && toValues != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
return true
}
- return layoutImpl.transitions
- .transitionSpec(fromScene, toScene)
- .transformations(element.key, scene.key)
- .alpha == null
+ return layoutImpl.state.transformationSpec.transformations(element.key, scene.key).alpha == null
}
/**
@@ -608,24 +597,22 @@ private inline fun <T> computeValue(
lastValue: () -> T,
lerp: (T, T, Float) -> T,
): T {
- val state = layoutImpl.state.transitionState
-
- // There is no ongoing transition.
- if (state !is TransitionState.Transition || state.fromScene == state.toScene) {
- // Even if this element SceneTransitionLayout is not animated, the layout itself might be
- // animated (e.g. by another parent SceneTransitionLayout), in which case this element still
- // need to participate in the layout phase.
- return currentValue()
- }
+ val transition =
+ layoutImpl.state.currentTransition
+ // There is no ongoing transition. Even if this element SceneTransitionLayout is not
+ // animated, the layout itself might be animated (e.g. by another parent
+ // SceneTransitionLayout), in which case this element still need to participate in the
+ // layout phase.
+ ?: return currentValue()
// A transition was started but it's not ready yet (not all elements have been composed/laid
// out yet). Use the last value that was set, to make sure elements don't unexpectedly jump.
- if (!layoutImpl.isTransitionReady(state)) {
+ if (!layoutImpl.isTransitionReady(transition)) {
return lastValue()
}
- val fromScene = state.fromScene
- val toScene = state.toScene
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromValues = element.sceneValues[fromScene]
val toValues = element.sceneValues[toScene]
@@ -639,21 +626,17 @@ private inline fun <T> computeValue(
// TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
// elements follow the finger direction.
val isSharedElement = fromValues != null && toValues != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
val start = sceneValue(fromValues!!)
val end = sceneValue(toValues!!)
// Make sure we don't read progress if values are the same and we don't need to interpolate,
// so we don't invalidate the phase where this is read.
- return if (start == end) start else lerp(start, end, state.progress)
+ return if (start == end) start else lerp(start, end, transition.progress)
}
val transformation =
- transformation(
- layoutImpl.transitions
- .transitionSpec(fromScene, toScene)
- .transformations(element.key, scene.key)
- )
+ transformation(layoutImpl.state.transformationSpec.transformations(element.key, scene.key))
// If there is no transformation explicitly associated to this element value, let's use
// the value given by the system (like the current position and size given by the layout
// pass).
@@ -676,7 +659,7 @@ private inline fun <T> computeValue(
scene,
element,
sceneValues,
- state,
+ transition,
idleValue,
)
@@ -686,7 +669,7 @@ private inline fun <T> computeValue(
return targetValue
}
- val progress = state.progress
+ val progress = transition.progress
// TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
val rangeProgress = transformation.range?.progress(progress) ?: progress
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index fa385d014ccb..306f27626e19 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -120,21 +120,13 @@ private fun shouldComposeMovableElement(
scene: SceneKey,
element: Element,
): Boolean {
- val transitionState = layoutImpl.state.transitionState
-
- // If we are idle, there is only one [scene] that is composed so we can compose our movable
- // content here.
- if (transitionState is TransitionState.Idle) {
- check(transitionState.currentScene == scene)
- return true
- }
-
- val fromScene = (transitionState as TransitionState.Transition).fromScene
- val toScene = transitionState.toScene
- if (fromScene == toScene) {
- check(fromScene == scene)
- return true
- }
+ val transition =
+ layoutImpl.state.currentTransition
+ // If we are idle, there is only one [scene] that is composed so we can compose our
+ // movable content here.
+ ?: return true
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromReady = layoutImpl.isSceneReady(fromScene)
val toReady = layoutImpl.isSceneReady(toScene)
@@ -185,10 +177,10 @@ private fun shouldComposeMovableElement(
return shouldDrawOrComposeSharedElement(
layoutImpl,
- transitionState,
+ transition,
scene,
element.key,
- sharedElementTransformation(layoutImpl, transitionState, element.key),
+ sharedElementTransformation(layoutImpl.state, transition, element.key),
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index ded6cc155b0b..e78f3266d664 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -73,37 +73,37 @@ enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
internal fun Modifier.nestedScrollToScene(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) =
this then
NestedScrollToSceneElement(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
private data class NestedScrollToSceneElement(
private val layoutImpl: SceneTransitionLayoutImpl,
private val orientation: Orientation,
- private val startBehavior: NestedScrollBehavior,
- private val endBehavior: NestedScrollBehavior,
+ private val topOrLeftBehavior: NestedScrollBehavior,
+ private val bottomOrRightBehavior: NestedScrollBehavior,
) : ModifierNodeElement<NestedScrollToSceneNode>() {
override fun create() =
NestedScrollToSceneNode(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
override fun update(node: NestedScrollToSceneNode) {
node.update(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
}
@@ -111,23 +111,23 @@ private data class NestedScrollToSceneElement(
name = "nestedScrollToScene"
properties["layoutImpl"] = layoutImpl
properties["orientation"] = orientation
- properties["startBehavior"] = startBehavior
- properties["endBehavior"] = endBehavior
+ properties["topOrLeftBehavior"] = topOrLeftBehavior
+ properties["bottomOrRightBehavior"] = bottomOrRightBehavior
}
}
private class NestedScrollToSceneNode(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) : DelegatingNode() {
private var priorityNestedScrollConnection: PriorityNestedScrollConnection =
scenePriorityNestedScrollConnection(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
private var nestedScrollNode: DelegatableNode =
@@ -148,8 +148,8 @@ private class NestedScrollToSceneNode(
fun update(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) {
// Clean up the old nested scroll connection
priorityNestedScrollConnection.reset()
@@ -160,8 +160,8 @@ private class NestedScrollToSceneNode(
scenePriorityNestedScrollConnection(
layoutImpl = layoutImpl,
orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
nestedScrollNode =
nestedScrollModifierNode(
@@ -175,12 +175,13 @@ private class NestedScrollToSceneNode(
private fun scenePriorityNestedScrollConnection(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ topOrLeftBehavior: NestedScrollBehavior,
+ bottomOrRightBehavior: NestedScrollBehavior,
) =
SceneNestedScrollHandler(
- gestureHandler = layoutImpl.gestureHandler(orientation = orientation),
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ layoutImpl = layoutImpl,
+ orientation = orientation,
+ topOrLeftBehavior = topOrLeftBehavior,
+ bottomOrRightBehavior = bottomOrRightBehavior,
)
.connection
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 1b79dbdee510..983cff83ed57 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -73,17 +73,13 @@ fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTrans
when (val state = transitionState) {
is TransitionState.Idle -> ObservableTransitionState.Idle(state.currentScene)
is TransitionState.Transition -> {
- if (state.fromScene == state.toScene) {
- ObservableTransitionState.Idle(state.currentScene)
- } else {
- ObservableTransitionState.Transition(
- fromScene = state.fromScene,
- toScene = state.toScene,
- progress = snapshotFlow { state.progress },
- isInitiatedByUserInput = state.isInitiatedByUserInput,
- isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
- )
- }
+ ObservableTransitionState.Transition(
+ fromScene = state.fromScene,
+ toScene = state.toScene,
+ progress = snapshotFlow { state.progress },
+ isInitiatedByUserInput = state.isInitiatedByUserInput,
+ isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
+ )
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
index f5561cb404b6..6a7a3a00d4fe 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
@@ -86,16 +86,26 @@ private class SceneScopeImpl(
return element(layoutImpl, scene, key)
}
- override fun Modifier.nestedScrollToScene(
- orientation: Orientation,
- startBehavior: NestedScrollBehavior,
- endBehavior: NestedScrollBehavior,
+ override fun Modifier.horizontalNestedScrollToScene(
+ leftBehavior: NestedScrollBehavior,
+ rightBehavior: NestedScrollBehavior,
): Modifier =
nestedScrollToScene(
layoutImpl = layoutImpl,
- orientation = orientation,
- startBehavior = startBehavior,
- endBehavior = endBehavior,
+ orientation = Orientation.Horizontal,
+ topOrLeftBehavior = leftBehavior,
+ bottomOrRightBehavior = rightBehavior,
+ )
+
+ override fun Modifier.verticalNestedScrollToScene(
+ topBehavior: NestedScrollBehavior,
+ bottomBehavior: NestedScrollBehavior
+ ): Modifier =
+ nestedScrollToScene(
+ layoutImpl = layoutImpl,
+ orientation = Orientation.Vertical,
+ topOrLeftBehavior = topBehavior,
+ bottomOrRightBehavior = bottomBehavior,
)
@Composable
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index 212c9eb65138..338557d0942e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -41,39 +41,37 @@ internal class SceneGestureHandler(
internal val orientation: Orientation,
private val coroutineScope: CoroutineScope,
) {
+ private val layoutState = layoutImpl.state
val draggable: DraggableHandler = SceneDraggableHandler(this)
- internal var transitionState
- get() = layoutImpl.state.transitionState
+ private var _swipeTransition: SwipeTransition? = null
+ internal var swipeTransition: SwipeTransition
+ get() = _swipeTransition ?: error("SwipeTransition needs to be initialized")
set(value) {
- layoutImpl.state.transitionState = value
+ _swipeTransition = value
}
- internal var swipeTransition: SwipeTransition = SwipeTransition(currentScene, currentScene, 1f)
- private set
-
private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
- if (isDrivingTransition || force) transitionState = newTransition
+ if (isDrivingTransition || force) layoutState.startTransition(newTransition)
swipeTransition = newTransition
}
- internal val currentScene: Scene
- get() = layoutImpl.scene(transitionState.currentScene)
-
internal val isDrivingTransition
- get() = transitionState == swipeTransition
+ get() = layoutState.transitionState == _swipeTransition
/**
* The velocity threshold at which the intent of the user is to swipe up or down. It is the same
* as SwipeableV2Defaults.VelocityThreshold.
*/
- internal val velocityThreshold = with(layoutImpl.density) { 125.dp.toPx() }
+ internal val velocityThreshold: Float
+ get() = with(layoutImpl.density) { 125.dp.toPx() }
/**
* The positional threshold at which the intent of the user is to swipe to the next scene. It is
* the same as SwipeableV2Defaults.PositionalThreshold.
*/
- private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
+ private val positionalThreshold
+ get() = with(layoutImpl.density) { 56.dp.toPx() }
internal var gestureWithPriority: Any? = null
@@ -82,34 +80,34 @@ internal class SceneGestureHandler(
private var actionDownOrRight: UserAction? = null
private var actionUpOrLeftNoEdge: UserAction? = null
private var actionDownOrRightNoEdge: UserAction? = null
+ private var upOrLeftScene: SceneKey? = null
+ private var downOrRightScene: SceneKey? = null
internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?, overSlop: Float) {
if (isDrivingTransition) {
// This [transition] was already driving the animation: simply take over it.
// Stop animating and start from where the current offset.
swipeTransition.cancelOffsetAnimation()
+ updateTargetScenes(swipeTransition._fromScene)
return
}
- val transition = transitionState
- if (transition is TransitionState.Transition) {
+ val transitionState = layoutState.transitionState
+ if (transitionState is TransitionState.Transition) {
// TODO(b/290184746): Better handle interruptions here if state != idle.
Log.w(
TAG,
"start from TransitionState.Transition is not fully supported: from" +
- " ${transition.fromScene} to ${transition.toScene} " +
- "(progress ${transition.progress})"
+ " ${transitionState.fromScene} to ${transitionState.toScene} " +
+ "(progress ${transitionState.progress})"
)
}
- val fromScene = currentScene
+ val fromScene = layoutImpl.scene(transitionState.currentScene)
setCurrentActions(fromScene, startedPosition, pointersDown)
- if (fromScene.upOrLeft() == null && fromScene.downOrRight() == null) {
- return
- }
-
- val (targetScene, distance) = fromScene.findTargetSceneAndDistance(overSlop)
+ val (targetScene, distance) =
+ findTargetSceneAndDistance(fromScene, overSlop, updateScenes = true) ?: return
updateTransition(SwipeTransition(fromScene, targetScene, distance), force = true)
}
@@ -179,16 +177,21 @@ internal class SceneGestureHandler(
val (fromScene, acceleratedOffset) =
computeFromSceneConsideringAcceleratedSwipe(swipeTransition)
- swipeTransition.dragOffset += acceleratedOffset
- // Compute the target scene depending on the current offset.
+ val isNewFromScene = fromScene.key != swipeTransition.fromScene
val (targetScene, distance) =
- fromScene.findTargetSceneAndDistance(swipeTransition.dragOffset)
+ findTargetSceneAndDistance(
+ fromScene,
+ swipeTransition.dragOffset,
+ updateScenes = isNewFromScene,
+ )
+ ?: run {
+ onDragStopped(delta, true)
+ return
+ }
+ swipeTransition.dragOffset += acceleratedOffset
- // TODO(b/290184746): support long scroll A => B => C? especially for non fullscreen scenes
- if (
- fromScene.key != swipeTransition.fromScene || targetScene.key != swipeTransition.toScene
- ) {
+ if (isNewFromScene || targetScene.key != swipeTransition.toScene) {
updateTransition(
SwipeTransition(fromScene, targetScene, distance).apply {
this.dragOffset = swipeTransition.dragOffset
@@ -197,6 +200,11 @@ internal class SceneGestureHandler(
}
}
+ private fun updateTargetScenes(fromScene: Scene) {
+ upOrLeftScene = fromScene.upOrLeft()
+ downOrRightScene = fromScene.downOrRight()
+ }
+
/**
* Change fromScene in the case where the user quickly swiped multiple times in the same
* direction to accelerate the transition from A => B then B => C.
@@ -214,37 +222,71 @@ internal class SceneGestureHandler(
val absoluteDistance = swipeTransition.distance.absoluteValue
// If the swipe was not committed, don't do anything.
- if (fromScene == toScene || swipeTransition._currentScene != toScene) {
+ if (swipeTransition._currentScene != toScene) {
return Pair(fromScene, 0f)
}
// If the offset is past the distance then let's change fromScene so that the user can swipe
// to the next screen or go back to the previous one.
val offset = swipeTransition.dragOffset
- return if (offset <= -absoluteDistance && fromScene.upOrLeft() == toScene.key) {
+ return if (offset <= -absoluteDistance && upOrLeftScene == toScene.key) {
Pair(toScene, absoluteDistance)
- } else if (offset >= absoluteDistance && fromScene.downOrRight() == toScene.key) {
+ } else if (offset >= absoluteDistance && downOrRightScene == toScene.key) {
Pair(toScene, -absoluteDistance)
} else {
Pair(fromScene, 0f)
}
}
- // TODO(b/290184746): there are two bugs here:
- // 1. if both upOrLeft and downOrRight become `null` during a transition this will crash
- // 2. if one of them changes during a transition, the transition will jump cut to the new target
- private inline fun Scene.findTargetSceneAndDistance(
- directionOffset: Float
- ): Pair<Scene, Float> {
- val upOrLeft = upOrLeft()
- val downOrRight = downOrRight()
- val absoluteDistance = getAbsoluteDistance()
+ /**
+ * Returns the target scene and distance from [fromScene] in the direction [directionOffset].
+ *
+ * @param fromScene the scene from which we look for the target
+ * @param directionOffset signed float that indicates the direction. Positive is down or right
+ * negative is up or left.
+ * @param updateScenes whether the target scenes should be updated to the current values held in
+ * the Scenes map. Usually we don't want to update them while doing a drag, because this could
+ * change the target scene (jump cutting) to a different scene, when some system state changed
+ * the targets the background. However, an update is needed any time we calculate the targets
+ * for a new fromScene.
+ * @return null when there are no targets in either direction. If one direction is null and you
+ * drag into the null direction this function will return the opposite direction, assuming
+ * that the users intention is to start the drag into the other direction eventually. If
+ * [directionOffset] is 0f and both direction are available, it will default to
+ * [upOrLeftScene].
+ */
+ private inline fun findTargetSceneAndDistance(
+ fromScene: Scene,
+ directionOffset: Float,
+ updateScenes: Boolean,
+ ): Pair<Scene, Float>? {
+ if (updateScenes) updateTargetScenes(fromScene)
+ val absoluteDistance = fromScene.getAbsoluteDistance()
// Compute the target scene depending on the current offset.
- return if ((directionOffset < 0f && upOrLeft != null) || downOrRight == null) {
- Pair(layoutImpl.scene(upOrLeft!!), -absoluteDistance)
- } else {
- Pair(layoutImpl.scene(downOrRight), absoluteDistance)
+ return when {
+ upOrLeftScene == null && downOrRightScene == null -> null
+ (directionOffset < 0f && upOrLeftScene != null) || downOrRightScene == null ->
+ Pair(layoutImpl.scene(upOrLeftScene!!), -absoluteDistance)
+ else -> Pair(layoutImpl.scene(downOrRightScene!!), absoluteDistance)
+ }
+ }
+
+ /**
+ * A strict version of [findTargetSceneAndDistance] that will return null when there is no Scene
+ * in [directionOffset] direction
+ */
+ private inline fun findTargetSceneAndDistanceStrict(
+ fromScene: Scene,
+ directionOffset: Float,
+ ): Pair<Scene, Float>? {
+ val absoluteDistance = fromScene.getAbsoluteDistance()
+ return when {
+ directionOffset > 0f ->
+ upOrLeftScene?.let { Pair(layoutImpl.scene(it), -absoluteDistance) }
+ directionOffset < 0f ->
+ downOrRightScene?.let { Pair(layoutImpl.scene(it), absoluteDistance) }
+ else -> null
}
}
@@ -311,20 +353,21 @@ internal class SceneGestureHandler(
val startFromIdlePosition = swipeTransition.dragOffset == 0f
if (startFromIdlePosition) {
- // If there is a next scene, we start the overscroll animation.
- val (targetScene, distance) = fromScene.findTargetSceneAndDistance(velocity)
- val isValidTarget = distance != 0f && targetScene.key != fromScene.key
- if (isValidTarget) {
- updateTransition(
- SwipeTransition(fromScene, targetScene, distance).apply {
- _currentScene = swipeTransition._currentScene
+ // If there is a target scene, we start the overscroll animation.
+ val (targetScene, distance) =
+ findTargetSceneAndDistanceStrict(fromScene, velocity)
+ ?: run {
+ // We will not animate
+ layoutState.finishTransition(swipeTransition, idleScene = fromScene.key)
+ return
}
- )
- animateTo(targetScene = fromScene, targetOffset = 0f)
- } else {
- // We will not animate
- transitionState = TransitionState.Idle(fromScene.key)
- }
+
+ updateTransition(
+ SwipeTransition(fromScene, targetScene, distance).apply {
+ _currentScene = swipeTransition._currentScene
+ }
+ )
+ animateTo(targetScene = fromScene, targetOffset = 0f)
} else {
// We were between two scenes: animate to the initial scene.
animateTo(targetScene = fromScene, targetOffset = 0f)
@@ -390,14 +433,7 @@ internal class SceneGestureHandler(
)
swipeTransition.finishOffsetAnimation()
-
- // Now that the animation is done, the state should be idle. Note that if the state
- // was changed since this animation started, some external code changed it and we
- // shouldn't do anything here. Note also that this job will be cancelled in the case
- // where the user intercepts this swipe.
- if (isDrivingTransition) {
- transitionState = TransitionState.Idle(targetScene)
- }
+ layoutState.finishTransition(swipeTransition, targetScene)
}
}
}
@@ -410,15 +446,11 @@ internal class SceneGestureHandler(
* above or to the left of [toScene].
*/
val distance: Float
- ) : TransitionState.Transition {
+ ) : TransitionState.Transition(_fromScene.key, _toScene.key) {
var _currentScene by mutableStateOf(_fromScene)
override val currentScene: SceneKey
get() = _currentScene.key
- override val fromScene: SceneKey = _fromScene.key
-
- override val toScene: SceneKey = _toScene.key
-
override val progress: Float
get() {
val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
@@ -494,10 +526,14 @@ private class SceneDraggableHandler(
}
internal class SceneNestedScrollHandler(
- private val gestureHandler: SceneGestureHandler,
- private val startBehavior: NestedScrollBehavior,
- private val endBehavior: NestedScrollBehavior,
+ private val layoutImpl: SceneTransitionLayoutImpl,
+ private val orientation: Orientation,
+ private val topOrLeftBehavior: NestedScrollBehavior,
+ private val bottomOrRightBehavior: NestedScrollBehavior,
) : NestedScrollHandler {
+ private val layoutState = layoutImpl.state
+ private val gestureHandler = layoutImpl.gestureHandler(orientation)
+
override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
private fun nestedScrollConnection(): PriorityNestedScrollConnection {
@@ -508,7 +544,7 @@ internal class SceneNestedScrollHandler(
val actionUpOrLeft =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Left
Orientation.Vertical -> SwipeDirection.Up
},
@@ -518,7 +554,7 @@ internal class SceneNestedScrollHandler(
val actionDownOrRight =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Right
Orientation.Vertical -> SwipeDirection.Down
},
@@ -526,7 +562,7 @@ internal class SceneNestedScrollHandler(
)
fun hasNextScene(amount: Float): Boolean {
- val fromScene = gestureHandler.currentScene
+ val fromScene = layoutImpl.scene(layoutState.transitionState.currentScene)
val nextScene =
when {
amount < 0f -> fromScene.userActions[actionUpOrLeft]
@@ -537,7 +573,7 @@ internal class SceneNestedScrollHandler(
}
return PriorityNestedScrollConnection(
- orientation = gestureHandler.orientation,
+ orientation = orientation,
canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
canChangeScene = offsetBeforeStart == 0f
@@ -545,8 +581,9 @@ internal class SceneNestedScrollHandler(
canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f
if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
- val progress = gestureHandler.swipeTransition.progress
- val threshold = gestureHandler.layoutImpl.transitionInterceptionThreshold
+ val swipeTransition = gestureHandler.swipeTransition
+ val progress = swipeTransition.progress
+ val threshold = layoutImpl.transitionInterceptionThreshold
fun isProgressCloseTo(value: Float) = (progress - value).absoluteValue <= threshold
// The transition is always between 0 and 1. If it is close to either of these
@@ -554,9 +591,8 @@ internal class SceneNestedScrollHandler(
// The progress value can go beyond this range in the case of overscroll.
val shouldSnapToIdle = isProgressCloseTo(0f) || isProgressCloseTo(1f)
if (shouldSnapToIdle) {
- gestureHandler.swipeTransition.cancelOffsetAnimation()
- gestureHandler.transitionState =
- TransitionState.Idle(gestureHandler.swipeTransition.currentScene)
+ swipeTransition.cancelOffsetAnimation()
+ layoutState.finishTransition(swipeTransition, swipeTransition.currentScene)
}
// Start only if we cannot consume this event
@@ -565,8 +601,8 @@ internal class SceneNestedScrollHandler(
canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
val behavior: NestedScrollBehavior =
when {
- offsetAvailable > 0f -> startBehavior
- offsetAvailable < 0f -> endBehavior
+ offsetAvailable > 0f -> topOrLeftBehavior
+ offsetAvailable < 0f -> bottomOrRightBehavior
else -> return@PriorityNestedScrollConnection false
}
@@ -594,8 +630,8 @@ internal class SceneNestedScrollHandler(
canStartPostFling = { velocityAvailable ->
val behavior: NestedScrollBehavior =
when {
- velocityAvailable > 0f -> startBehavior
- velocityAvailable < 0f -> endBehavior
+ velocityAvailable > 0f -> topOrLeftBehavior
+ velocityAvailable < 0f -> bottomOrRightBehavior
else -> return@PriorityNestedScrollConnection false
}
@@ -604,6 +640,7 @@ internal class SceneNestedScrollHandler(
behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
},
canContinueScroll = { true },
+ canScrollOnFling = false,
onStart = { offsetAvailable ->
gestureHandler.gestureWithPriority = this
gestureHandler.onDragStarted(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index afa184b15901..3608e374fdbc 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -19,6 +19,8 @@ package com.android.compose.animation.scene
import androidx.annotation.FloatRange
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
@@ -27,6 +29,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.platform.LocalDensity
+import kotlinx.coroutines.channels.Channel
/**
* [SceneTransitionLayout] is a container that automatically animates its content whenever
@@ -126,14 +129,24 @@ interface SceneScope {
* Adds a [NestedScrollConnection] to intercept scroll events not handled by the scrollable
* component.
*
- * @param orientation is used to determine if we handle top/bottom or left/right events.
- * @param startBehavior when we should perform the overscroll animation at the top/left.
- * @param endBehavior when we should perform the overscroll animation at the bottom/right.
+ * @param leftBehavior when we should perform the overscroll animation at the left.
+ * @param rightBehavior when we should perform the overscroll animation at the right.
*/
- fun Modifier.nestedScrollToScene(
- orientation: Orientation,
- startBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
- endBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ fun Modifier.horizontalNestedScrollToScene(
+ leftBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ rightBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ ): Modifier
+
+ /**
+ * Adds a [NestedScrollConnection] to intercept scroll events not handled by the scrollable
+ * component.
+ *
+ * @param topBehavior when we should perform the overscroll animation at the top.
+ * @param bottomBehavior when we should perform the overscroll animation at the bottom.
+ */
+ fun Modifier.verticalNestedScrollToScene(
+ topBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
+ bottomBehavior: NestedScrollBehavior = NestedScrollBehavior.EdgeNoPreview,
): Modifier
/**
@@ -256,24 +269,45 @@ internal fun SceneTransitionLayoutForTesting(
val coroutineScope = rememberCoroutineScope()
val layoutImpl = remember {
SceneTransitionLayoutImpl(
+ state = state as SceneTransitionLayoutStateImpl,
onChangeScene = onChangeScene,
- builder = scenes,
- transitions = transitions,
- state = state,
density = density,
edgeDetector = edgeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
+ builder = scenes,
coroutineScope = coroutineScope,
)
.also { onLayoutImpl?.invoke(it) }
}
- layoutImpl.onChangeScene = onChangeScene
- layoutImpl.transitions = transitions
- layoutImpl.density = density
- layoutImpl.edgeDetector = edgeDetector
+ val targetSceneChannel = remember { Channel<SceneKey>(Channel.CONFLATED) }
+ SideEffect {
+ if (state != layoutImpl.state) {
+ error(
+ "This SceneTransitionLayout was bound to a different SceneTransitionLayoutState" +
+ " that was used when creating it, which is not supported"
+ )
+ }
+
+ layoutImpl.onChangeScene = onChangeScene
+ (state as SceneTransitionLayoutStateImpl).transitions = transitions
+ layoutImpl.density = density
+ layoutImpl.edgeDetector = edgeDetector
+ layoutImpl.updateScenes(scenes)
+
+ state.transitions = transitions
+
+ targetSceneChannel.trySend(currentScene)
+ }
+
+ LaunchedEffect(targetSceneChannel) {
+ for (newKey in targetSceneChannel) {
+ // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame
+ // late.
+ val newKey = targetSceneChannel.tryReceive().getOrNull() ?: newKey
+ animateToScene(layoutImpl.state, newKey)
+ }
+ }
- layoutImpl.setScenes(scenes)
- layoutImpl.setCurrentScene(currentScene)
layoutImpl.Content(modifier)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 02ddccbc051b..c99c3250bbb1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -22,13 +22,8 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -40,36 +35,40 @@ import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
import com.android.compose.ui.util.lerp
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.channels.Channel
@Stable
internal class SceneTransitionLayoutImpl(
- onChangeScene: (SceneKey) -> Unit,
+ internal val state: SceneTransitionLayoutStateImpl,
+ internal var onChangeScene: (SceneKey) -> Unit,
+ internal var density: Density,
+ internal var edgeDetector: EdgeDetector,
+ internal var transitionInterceptionThreshold: Float,
builder: SceneTransitionLayoutScope.() -> Unit,
- transitions: SceneTransitions,
- internal val state: SceneTransitionLayoutState,
- density: Density,
- edgeDetector: EdgeDetector,
- transitionInterceptionThreshold: Float,
coroutineScope: CoroutineScope,
) {
- internal val scenes = SnapshotStateMap<SceneKey, Scene>()
+ internal val scenes = mutableMapOf<SceneKey, Scene>()
+
+ /**
+ * The map of [Element]s.
+ *
+ * Note that this map is *mutated* directly during composition, so it is a [SnapshotStateMap] to
+ * make sure that mutations are reverted if composition is cancelled.
+ */
internal val elements = SnapshotStateMap<ElementKey, Element>()
- /** The scenes that are "ready", i.e. they were composed and fully laid-out at least once. */
+ /**
+ * The scenes that are "ready", i.e. they were composed and fully laid-out at least once.
+ *
+ * Note that this map is *read* during composition, so it is a [SnapshotStateMap] to make sure
+ * that we recompose when modifications are made to this map.
+ */
private val readyScenes = SnapshotStateMap<SceneKey, Boolean>()
- internal var onChangeScene by mutableStateOf(onChangeScene)
- internal var transitions by mutableStateOf(transitions)
- internal var density: Density by mutableStateOf(density)
- internal var edgeDetector by mutableStateOf(edgeDetector)
- internal var transitionInterceptionThreshold by mutableStateOf(transitionInterceptionThreshold)
-
private val horizontalGestureHandler: SceneGestureHandler
private val verticalGestureHandler: SceneGestureHandler
init {
- setScenes(builder)
+ updateScenes(builder)
// SceneGestureHandler must wait for the scenes to be initialized, in order to access the
// current scene (required for SwipeTransition).
@@ -98,7 +97,7 @@ internal class SceneTransitionLayoutImpl(
return scenes[key] ?: error("Scene $key is not configured")
}
- internal fun setScenes(builder: SceneTransitionLayoutScope.() -> Unit) {
+ internal fun updateScenes(builder: SceneTransitionLayoutScope.() -> Unit) {
// Keep a reference of the current scenes. After processing [builder], the scenes that were
// not configured will be removed.
val scenesToRemove = scenes.keys.toMutableSet()
@@ -141,20 +140,6 @@ internal class SceneTransitionLayoutImpl(
}
@Composable
- internal fun setCurrentScene(key: SceneKey) {
- val channel = remember { Channel<SceneKey>(Channel.CONFLATED) }
- SideEffect { channel.trySend(key) }
- LaunchedEffect(channel) {
- for (newKey in channel) {
- // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame
- // late.
- val newKey = channel.tryReceive().getOrNull() ?: newKey
- animateToScene(this@SceneTransitionLayoutImpl, newKey)
- }
- }
- }
-
- @Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun Content(modifier: Modifier) {
Box(
@@ -171,14 +156,14 @@ internal class SceneTransitionLayoutImpl(
val width: Int
val height: Int
- val state = state.transitionState
- if (state !is TransitionState.Transition || state.fromScene == state.toScene) {
+ val transition = state.currentTransition
+ if (transition == null) {
width = placeable.width
height = placeable.height
} else {
// Interpolate the size.
- val fromSize = scene(state.fromScene).targetSize
- val toSize = scene(state.toScene).targetSize
+ val fromSize = scene(transition.fromScene).targetSize
+ val toSize = scene(transition.toScene).targetSize
// Optimization: make sure we don't read state.progress if fromSize ==
// toSize to avoid running this code every frame when the layout size does
@@ -187,7 +172,7 @@ internal class SceneTransitionLayoutImpl(
width = fromSize.width
height = fromSize.height
} else {
- val size = lerp(fromSize, toSize, state.progress)
+ val size = lerp(fromSize, toSize, transition.progress)
width = size.width.coerceAtLeast(0)
height = size.height.coerceAtLeast(0)
}
@@ -228,16 +213,12 @@ internal class SceneTransitionLayoutImpl(
scene.Content(
Modifier.drawWithContent {
- when (val state = state.transitionState) {
- is TransitionState.Idle -> drawContent()
- is TransitionState.Transition -> {
- // Don't draw scenes that are not ready yet.
- if (
- readyScenes.containsKey(key) ||
- state.fromScene == state.toScene
- ) {
- drawContent()
- }
+ if (state.currentTransition == null) {
+ drawContent()
+ } else {
+ // Don't draw scenes that are not ready yet.
+ if (readyScenes.containsKey(key)) {
+ drawContent()
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index f48e9147eef4..d1ba582d6c23 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -23,36 +23,32 @@ import androidx.compose.runtime.setValue
/** The state of a [SceneTransitionLayout]. */
@Stable
-class SceneTransitionLayoutState(initialScene: SceneKey) {
+sealed interface SceneTransitionLayoutState {
/**
* The current [TransitionState]. All values read here are backed by the Snapshot system.
*
* To observe those values outside of Compose/the Snapshot system, use
* [SceneTransitionLayoutState.observableTransitionState] instead.
*/
- var transitionState: TransitionState by mutableStateOf(TransitionState.Idle(initialScene))
+ val transitionState: TransitionState
+
+ /** The current transition, or `null` if we are idle. */
+ val currentTransition: TransitionState.Transition?
+ get() = transitionState as? TransitionState.Transition
/**
- * Whether we are transitioning, optionally restricting the check to the transition between
- * [from] and [to].
+ * Whether we are transitioning. If [from] or [to] is empty, we will also check that they match
+ * the scenes we are animating from and/or to.
*/
- fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean {
- val transition = transitionState as? TransitionState.Transition ?: return false
-
- // TODO(b/310915136): Remove this check.
- if (transition.fromScene == transition.toScene) {
- return false
- }
-
- return (from == null || transition.fromScene == from) &&
- (to == null || transition.toScene == to)
- }
+ fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean
/** Whether we are transitioning from [scene] to [other], or from [other] to [scene]. */
- fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean {
- return isTransitioning(from = scene, to = other) ||
- isTransitioning(from = other, to = scene)
- }
+ fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean
+}
+
+/** Create a new [SceneTransitionLayoutState] that is currently idle at scene [currentScene]. */
+fun SceneTransitionLayoutState(currentScene: SceneKey): SceneTransitionLayoutState {
+ return SceneTransitionLayoutStateImpl(currentScene, SceneTransitions.Empty)
}
@Stable
@@ -71,32 +67,77 @@ sealed interface TransitionState {
/** No transition/animation is currently running. */
data class Idle(override val currentScene: SceneKey) : TransitionState
- /**
- * There is a transition animating between two scenes.
- *
- * Important note: [fromScene] and [toScene] might be the same, in which case this [Transition]
- * should be treated the same as [Idle]. This is designed on purpose so that a [Transition] can
- * be started without knowing in advance where it is transitioning to, making the logic of
- * [swipeToScene] easier to reason about.
- */
- interface Transition : TransitionState {
- /** The scene this transition is starting from. */
- val fromScene: SceneKey
+ /** There is a transition animating between two scenes. */
+ abstract class Transition(
+ /** The scene this transition is starting from. Can't be the same as toScene */
+ val fromScene: SceneKey,
- /** The scene this transition is going to. */
+ /** The scene this transition is going to. Can't be the same as fromScene */
val toScene: SceneKey
+ ) : TransitionState {
+
+ init {
+ check(fromScene != toScene)
+ }
/**
* The progress of the transition. This is usually in the `[0; 1]` range, but it can also be
* less than `0` or greater than `1` when using transitions with a spring AnimationSpec or
* when flinging quickly during a swipe gesture.
*/
- val progress: Float
+ abstract val progress: Float
/** Whether the transition was triggered by user input rather than being programmatic. */
- val isInitiatedByUserInput: Boolean
+ abstract val isInitiatedByUserInput: Boolean
/** Whether user input is currently driving the transition. */
- val isUserInputOngoing: Boolean
+ abstract val isUserInputOngoing: Boolean
+ }
+}
+
+internal class SceneTransitionLayoutStateImpl(
+ initialScene: SceneKey,
+ internal var transitions: SceneTransitions,
+) : SceneTransitionLayoutState {
+ override var transitionState: TransitionState by
+ mutableStateOf(TransitionState.Idle(initialScene))
+ private set
+
+ /**
+ * The current [transformationSpec] associated to [transitionState]. Accessing this value makes
+ * sense only if [transitionState] is a [TransitionState.Transition].
+ */
+ internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+
+ override fun isTransitioning(from: SceneKey?, to: SceneKey?): Boolean {
+ val transition = currentTransition ?: return false
+ return (from == null || transition.fromScene == from) &&
+ (to == null || transition.toScene == to)
+ }
+
+ override fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean {
+ return isTransitioning(from = scene, to = other) ||
+ isTransitioning(from = other, to = scene)
+ }
+
+ /** Start a new [transition], instantly interrupting any ongoing transition if there was one. */
+ internal fun startTransition(transition: TransitionState.Transition) {
+ // Compute the [TransformationSpec] when the transition starts.
+ transformationSpec =
+ transitions
+ .transitionSpec(transition.fromScene, transition.toScene)
+ .transformationSpec()
+
+ transitionState = transition
+ }
+
+ /**
+ * Notify that [transition] was finished and that we should settle to [idleScene]. This will do
+ * nothing if [transition] was interrupted since it was started.
+ */
+ internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
+ if (transitionState == transition) {
+ transitionState = TransitionState.Idle(idleScene)
+ }
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index f91895bb0e05..3a55567d69bb 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -18,11 +18,9 @@ package com.android.compose.animation.scene
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.snap
-import androidx.compose.runtime.Stable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
-import androidx.compose.ui.util.fastMap
import com.android.compose.animation.scene.transformation.AnchoredSize
import com.android.compose.animation.scene.transformation.AnchoredTranslate
import com.android.compose.animation.scene.transformation.DrawScale
@@ -36,16 +34,17 @@ import com.android.compose.animation.scene.transformation.Transformation
import com.android.compose.animation.scene.transformation.Translate
/** The transitions configuration of a [SceneTransitionLayout]. */
-class SceneTransitions(
- internal val transitionSpecs: List<TransitionSpec>,
+class SceneTransitions
+internal constructor(
+ internal val transitionSpecs: List<TransitionSpecImpl>,
) {
- private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpec>>()
+ private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpecImpl>>()
- internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpec {
+ internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpecImpl {
return cache.getOrPut(from) { mutableMapOf() }.getOrPut(to) { findSpec(from, to) }
}
- private fun findSpec(from: SceneKey, to: SceneKey): TransitionSpec {
+ private fun findSpec(from: SceneKey, to: SceneKey): TransitionSpecImpl {
val spec = transition(from, to) { it.from == from && it.to == to }
if (spec != null) {
return spec
@@ -53,7 +52,7 @@ class SceneTransitions(
val reversed = transition(from, to) { it.from == to && it.to == from }
if (reversed != null) {
- return reversed.reverse()
+ return reversed.reversed()
}
val relaxedSpec =
@@ -67,16 +66,16 @@ class SceneTransitions(
return transition(from, to) {
(it.from == to && it.to == null) || (it.to == from && it.from == null)
}
- ?.reverse()
+ ?.reversed()
?: defaultTransition(from, to)
}
private fun transition(
from: SceneKey,
to: SceneKey,
- filter: (TransitionSpec) -> Boolean,
- ): TransitionSpec? {
- var match: TransitionSpec? = null
+ filter: (TransitionSpecImpl) -> Boolean,
+ ): TransitionSpecImpl? {
+ var match: TransitionSpecImpl? = null
transitionSpecs.fastForEach { spec ->
if (filter(spec)) {
if (match != null) {
@@ -89,28 +88,88 @@ class SceneTransitions(
}
private fun defaultTransition(from: SceneKey, to: SceneKey) =
- TransitionSpec(from, to, emptyList(), snap())
+ TransitionSpecImpl(from, to, TransformationSpec.EmptyProvider)
+
+ companion object {
+ val Empty = SceneTransitions(transitionSpecs = emptyList())
+ }
}
/** The definition of a transition between [from] and [to]. */
-@Stable
-data class TransitionSpec(
- val from: SceneKey?,
- val to: SceneKey?,
- val transformations: List<Transformation>,
- val spec: AnimationSpec<Float>,
-) {
- // TODO(b/302300957): Make sure this cache does not infinitely grow.
- private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
+interface TransitionSpec {
+ /**
+ * The scene we are transitioning from. If `null`, this spec can be used to animate from any
+ * scene.
+ */
+ val from: SceneKey?
+
+ /**
+ * The scene we are transitioning to. If `null`, this spec can be used to animate from any
+ * scene.
+ */
+ val to: SceneKey?
+
+ /**
+ * Return a reversed version of this [TransitionSpec] for a transition going from [to] to
+ * [from].
+ */
+ fun reversed(): TransitionSpec
+
+ /*
+ * The [TransformationSpec] associated to this [TransitionSpec].
+ *
+ * Note that this is called once every a transition associated to this [TransitionSpec] is
+ * started.
+ */
+ fun transformationSpec(): TransformationSpec
+}
+
+interface TransformationSpec {
+ /** The [AnimationSpec] used to animate the associated transition progress. */
+ val progressSpec: AnimationSpec<Float>
+
+ /** The list of [Transformation] applied to elements during this transition. */
+ val transformations: List<Transformation>
+
+ companion object {
+ internal val Empty =
+ TransformationSpecImpl(progressSpec = snap(), transformations = emptyList())
+ internal val EmptyProvider = { Empty }
+ }
+}
- internal fun reverse(): TransitionSpec {
- return copy(
+internal class TransitionSpecImpl(
+ override val from: SceneKey?,
+ override val to: SceneKey?,
+ private val transformationSpec: () -> TransformationSpecImpl,
+) : TransitionSpec {
+ override fun reversed(): TransitionSpecImpl {
+ return TransitionSpecImpl(
from = to,
to = from,
- transformations = transformations.fastMap { it.reverse() },
+ transformationSpec = {
+ val reverse = transformationSpec.invoke()
+ TransformationSpecImpl(
+ progressSpec = reverse.progressSpec,
+ transformations = reverse.transformations.map { it.reversed() }
+ )
+ }
)
}
+ override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke()
+}
+
+/**
+ * An implementation of [TransformationSpec] that allows the quick retrieval of an element
+ * [ElementTransformations].
+ */
+internal class TransformationSpecImpl(
+ override val progressSpec: AnimationSpec<Float>,
+ override val transformations: List<Transformation>,
+) : TransformationSpec {
+ private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
+
internal fun transformations(element: ElementKey, scene: SceneKey): ElementTransformations {
return cache
.getOrPut(element) { mutableMapOf() }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 116a66673d0a..0d3bc7d0cd85 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -27,7 +27,8 @@ internal fun Modifier.swipeToScene(gestureHandler: SceneGestureHandler): Modifie
fun Scene.shouldEnableSwipes(orientation: Orientation): Boolean =
userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
- val currentScene = gestureHandler.currentScene
+ val layoutImpl = gestureHandler.layoutImpl
+ val currentScene = layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
val orientation = gestureHandler.orientation
val canSwipe = currentScene.shouldEnableSwipes(orientation)
val canOppositeSwipe =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 8f4a36e47212..70468669297c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -44,7 +44,7 @@ internal fun transitionsImpl(
}
private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
- val transitionSpecs = mutableListOf<TransitionSpec>()
+ val transitionSpecs = mutableListOf<TransitionSpecImpl>()
override fun to(to: SceneKey, builder: TransitionBuilder.() -> Unit): TransitionSpec {
return transition(from = null, to = to, builder)
@@ -63,14 +63,15 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
to: SceneKey?,
builder: TransitionBuilder.() -> Unit,
): TransitionSpec {
- val impl = TransitionBuilderImpl().apply(builder)
- val spec =
- TransitionSpec(
- from,
- to,
- impl.transformations,
- impl.spec,
+ fun transformationSpec(): TransformationSpecImpl {
+ val impl = TransitionBuilderImpl().apply(builder)
+ return TransformationSpecImpl(
+ progressSpec = impl.spec,
+ transformations = impl.transformations,
)
+ }
+
+ val spec = TransitionSpecImpl(from, to, ::transformationSpec)
transitionSpecs.add(spec)
return spec
}
@@ -143,7 +144,7 @@ internal class TransitionBuilderImpl : TransitionBuilder {
transformations.add(
if (reversed) {
- transformation.reverse()
+ transformation.reversed()
} else {
transformation
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 206935558179..0cd11b9914c9 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -42,7 +42,7 @@ sealed interface Transformation {
* Reverse this transformation. This is called when we use Transition(from = A, to = B) when
* animating from B to A and there is no Transition(from = B, to = A) defined.
*/
- fun reverse(): Transformation = this
+ fun reversed(): Transformation = this
}
internal class SharedElementTransformation(
@@ -77,10 +77,10 @@ internal class RangedPropertyTransformation<T>(
val delegate: PropertyTransformation<T>,
override val range: TransformationRange,
) : PropertyTransformation<T> by delegate {
- override fun reverse(): Transformation {
+ override fun reversed(): Transformation {
return RangedPropertyTransformation(
- delegate.reverse() as PropertyTransformation<T>,
- range.reverse()
+ delegate.reversed() as PropertyTransformation<T>,
+ range.reversed()
)
}
}
@@ -102,7 +102,7 @@ data class TransformationRange(
}
/** Reverse this range. */
- fun reverse() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
+ fun reversed() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
/** Get the progress of this range given the global [transitionProgress]. */
fun progress(transitionProgress: Float): Float {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
index cea8d9a65b43..2c96d0e5402a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
@@ -16,9 +16,8 @@
package com.android.compose.nestedscroll
-import androidx.compose.ui.geometry.Offset
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
/**
* A [NestedScrollConnection] that listens for all vertical scroll events and responds in the
@@ -34,59 +33,44 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource
*
* @sample com.android.compose.animation.scene.demo.Shade
*/
-class LargeTopAppBarNestedScrollConnection(
- private val height: () -> Float,
- private val onChangeHeight: (Float) -> Unit,
- private val minHeight: Float,
- private val maxHeight: Float,
-) : NestedScrollConnection {
-
- constructor(
- height: () -> Float,
- onHeightChanged: (Float) -> Unit,
- heightRange: ClosedFloatingPointRange<Float>,
- ) : this(
- height = height,
- onChangeHeight = onHeightChanged,
- minHeight = heightRange.start,
- maxHeight = heightRange.endInclusive,
+fun LargeTopAppBarNestedScrollConnection(
+ height: () -> Float,
+ onHeightChanged: (Float) -> Unit,
+ heightRange: ClosedFloatingPointRange<Float>,
+): PriorityNestedScrollConnection {
+ val minHeight = heightRange.start
+ val maxHeight = heightRange.endInclusive
+ return PriorityNestedScrollConnection(
+ orientation = Orientation.Vertical,
+ // When swiping up, the LargeTopAppBar will shrink (to [minHeight]) and the content will
+ // expand. Then, you can then scroll down the content.
+ canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
+ offsetAvailable < 0 && offsetBeforeStart == 0f && height() > minHeight
+ },
+ // When swiping down, the content will scroll up until it reaches the top. Then, the
+ // LargeTopAppBar will expand until it reaches its [maxHeight].
+ canStartPostScroll = { offsetAvailable, _ -> offsetAvailable > 0 && height() < maxHeight },
+ canStartPostFling = { false },
+ canContinueScroll = {
+ val currentHeight = height()
+ minHeight < currentHeight && currentHeight < maxHeight
+ },
+ canScrollOnFling = true,
+ onStart = { /* do nothing */},
+ onScroll = { offsetAvailable ->
+ val currentHeight = height()
+ val amountConsumed =
+ if (offsetAvailable > 0) {
+ val amountLeft = maxHeight - currentHeight
+ offsetAvailable.coerceAtMost(amountLeft)
+ } else {
+ val amountLeft = minHeight - currentHeight
+ offsetAvailable.coerceAtLeast(amountLeft)
+ }
+ onHeightChanged(currentHeight + amountConsumed)
+ amountConsumed
+ },
+ // Don't consume the velocity on pre/post fling
+ onStop = { 0f },
)
-
- /**
- * When swiping up, the LargeTopAppBar will shrink (to [minHeight]) and the content will expand.
- * Then, you can then scroll down the content.
- */
- override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
- val y = available.y
- val currentHeight = height()
- if (y >= 0 || currentHeight <= minHeight) {
- return Offset.Zero
- }
-
- val amountLeft = minHeight - currentHeight
- val amountConsumed = y.coerceAtLeast(amountLeft)
- onChangeHeight(currentHeight + amountConsumed)
- return Offset(0f, amountConsumed)
- }
-
- /**
- * When swiping down, the content will scroll up until it reaches the top. Then, the
- * LargeTopAppBar will expand until it reaches its [maxHeight].
- */
- override fun onPostScroll(
- consumed: Offset,
- available: Offset,
- source: NestedScrollSource
- ): Offset {
- val y = available.y
- val currentHeight = height()
- if (y <= 0 || currentHeight >= maxHeight) {
- return Offset.Zero
- }
-
- val amountLeft = maxHeight - currentHeight
- val amountConsumed = y.coerceAtMost(amountLeft)
- onChangeHeight(currentHeight + amountConsumed)
- return Offset(0f, amountConsumed)
- }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index c49a2b8bbe32..2841bcf4e40c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -38,6 +38,7 @@ class PriorityNestedScrollConnection(
private val canStartPostScroll: (offsetAvailable: Offset, offsetBeforeStart: Offset) -> Boolean,
private val canStartPostFling: (velocityAvailable: Velocity) -> Boolean,
private val canContinueScroll: () -> Boolean,
+ private val canScrollOnFling: Boolean,
private val onStart: (offsetAvailable: Offset) -> Unit,
private val onScroll: (offsetAvailable: Offset) -> Offset,
private val onStop: (velocityAvailable: Velocity) -> Velocity,
@@ -59,7 +60,7 @@ class PriorityNestedScrollConnection(
if (
isPriorityMode ||
- source == NestedScrollSource.Fling ||
+ (source == NestedScrollSource.Fling && !canScrollOnFling) ||
!canStartPostScroll(available, offsetBeforeStart)
) {
// The priority mode cannot start so we won't consume the available offset.
@@ -71,7 +72,7 @@ class PriorityNestedScrollConnection(
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
if (!isPriorityMode) {
- if (source != NestedScrollSource.Fling) {
+ if (source != NestedScrollSource.Fling || canScrollOnFling) {
if (canStartPreScroll(available, offsetScrolledBeforePriorityMode)) {
return onPriorityStart(available)
}
@@ -98,12 +99,20 @@ class PriorityNestedScrollConnection(
}
override suspend fun onPreFling(available: Velocity): Velocity {
+ if (isPriorityMode && canScrollOnFling) {
+ // We don't want to consume the velocity, we prefer to continue receiving scroll events.
+ return Velocity.Zero
+ }
// Step 3b: The finger is lifted, we can stop intercepting scroll events and use the speed
// of the fling gesture.
return onPriorityStop(velocity = available)
}
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+ if (isPriorityMode) {
+ return onPriorityStop(velocity = available)
+ }
+
if (!canStartPostFling(available)) {
return Velocity.Zero
}
@@ -156,6 +165,7 @@ fun PriorityNestedScrollConnection(
canStartPostScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
canStartPostFling: (velocityAvailable: Float) -> Boolean,
canContinueScroll: () -> Boolean,
+ canScrollOnFling: Boolean,
onStart: (offsetAvailable: Float) -> Unit,
onScroll: (offsetAvailable: Float) -> Float,
onStop: (velocityAvailable: Float) -> Float,
@@ -172,6 +182,7 @@ fun PriorityNestedScrollConnection(
canStartPostFling(velocityAvailable.toFloat())
},
canContinueScroll = canContinueScroll,
+ canScrollOnFling = canScrollOnFling,
onStart = { offsetAvailable -> onStart(offsetAvailable.toFloat()) },
onScroll = { offsetAvailable: Offset ->
onScroll(offsetAvailable.toFloat()).toOffset()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index aa942e039856..d9ce5191f3d9 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -55,19 +55,25 @@ class SceneGestureHandlerTest {
) {
private var internalCurrentScene: SceneKey by mutableStateOf(SceneA)
- private val layoutState: SceneTransitionLayoutState =
- SceneTransitionLayoutState(internalCurrentScene)
+ private val layoutState =
+ SceneTransitionLayoutStateImpl(internalCurrentScene, EmptyTestTransitions)
+
+ val mutableUserActionsA: MutableMap<UserAction, SceneKey> =
+ mutableMapOf(Swipe.Up to SceneB, Swipe.Down to SceneC)
+
+ val mutableUserActionsB: MutableMap<UserAction, SceneKey> =
+ mutableMapOf(Swipe.Up to SceneC, Swipe.Down to SceneA)
private val scenesBuilder: SceneTransitionLayoutScope.() -> Unit = {
scene(
key = SceneA,
- userActions = mapOf(Swipe.Up to SceneB, Swipe.Down to SceneC),
+ userActions = mutableUserActionsA,
) {
Text("SceneA")
}
scene(
key = SceneB,
- userActions = mapOf(Swipe.Up to SceneC, Swipe.Down to SceneA),
+ userActions = mutableUserActionsB,
) {
Text("SceneB")
}
@@ -87,38 +93,26 @@ class SceneGestureHandlerTest {
private val layoutImpl =
SceneTransitionLayoutImpl(
- onChangeScene = { internalCurrentScene = it },
- builder = scenesBuilder,
- transitions = EmptyTestTransitions,
state = layoutState,
+ onChangeScene = { internalCurrentScene = it },
density = Density(1f),
edgeDetector = DefaultEdgeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
+ builder = scenesBuilder,
coroutineScope = coroutineScope,
)
.apply { setScenesTargetSizeForTest(LAYOUT_SIZE) }
- val sceneGestureHandler =
- SceneGestureHandler(
- layoutImpl = layoutImpl,
- orientation = Orientation.Vertical,
- coroutineScope = coroutineScope,
- )
-
- val horizontalSceneGestureHandler =
- SceneGestureHandler(
- layoutImpl = layoutImpl,
- orientation = Orientation.Horizontal,
- coroutineScope = coroutineScope,
- )
-
+ val sceneGestureHandler = layoutImpl.gestureHandler(Orientation.Vertical)
+ val horizontalSceneGestureHandler = layoutImpl.gestureHandler(Orientation.Horizontal)
val draggable = sceneGestureHandler.draggable
fun nestedScrollConnection(nestedScrollBehavior: NestedScrollBehavior) =
SceneNestedScrollHandler(
- gestureHandler = sceneGestureHandler,
- startBehavior = nestedScrollBehavior,
- endBehavior = nestedScrollBehavior,
+ layoutImpl,
+ orientation = sceneGestureHandler.orientation,
+ topOrLeftBehavior = nestedScrollBehavior,
+ bottomOrRightBehavior = nestedScrollBehavior,
)
.connection
@@ -412,6 +406,70 @@ class SceneGestureHandlerTest {
}
@Test
+ fun onAccelaratedScrollBothTargetsBecomeNull_settlesToIdle() = runGestureTest {
+ draggable.onDragStarted()
+ draggable.onDelta(up(0.2f))
+
+ draggable.onDelta(up(0.2f))
+ draggable.onDragStopped(velocity = -velocityThreshold)
+ assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB)
+
+ mutableUserActionsA.remove(Swipe.Up)
+ mutableUserActionsA.remove(Swipe.Down)
+ mutableUserActionsB.remove(Swipe.Up)
+ mutableUserActionsB.remove(Swipe.Down)
+
+ // start accelaratedScroll and scroll over to B -> null
+ draggable.onDragStarted()
+ draggable.onDelta(up(0.5f))
+ draggable.onDelta(up(0.5f))
+
+ // here onDragStopped is already triggered, but subsequent onDelta/onDragStopped calls may
+ // still be called. Make sure that they don't crash or change the scene
+ draggable.onDelta(up(0.5f))
+ draggable.onDragStopped(0f)
+
+ advanceUntilIdle()
+ assertIdle(SceneB)
+
+ // These events can still come in after the animation has settled
+ draggable.onDelta(up(0.5f))
+ draggable.onDragStopped(0f)
+ assertIdle(SceneB)
+ }
+
+ @Test
+ fun onDragTargetsChanged_targetStaysTheSame() = runGestureTest {
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)
+
+ mutableUserActionsA[Swipe.Up] = SceneC
+ draggable.onDelta(up(0.1f))
+ // target stays B even though UserActions changed
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.2f)
+ draggable.onDragStopped(down(0.1f))
+ advanceUntilIdle()
+
+ // now target changed to C for new drag
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.1f)
+ }
+
+ @Test
+ fun onDragTargetsChanged_targetsChangeWhenStartingNewDrag() = runGestureTest {
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)
+
+ mutableUserActionsA[Swipe.Up] = SceneC
+ draggable.onDelta(up(0.1f))
+ draggable.onDragStopped(down(0.1f))
+
+ // now target changed to C for new drag that started before previous drag settled to Idle
+ draggable.onDragStarted(up(0.1f))
+ assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.3f)
+ }
+
+ @Test
fun startGestureDuringAnimatingOffset_shouldImmediatelyStopTheAnimation() = runGestureTest {
draggable.onDragStarted()
assertTransition(currentScene = SceneA)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 94c51ca50667..c5b8d9ae0d10 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -39,21 +39,9 @@ class SceneTransitionLayoutStateTest {
}
@Test
- fun isTransitioningTo_fromSceneEqualToToScene() {
- val state = SceneTransitionLayoutState(TestScenes.SceneA)
- state.transitionState = transition(from = TestScenes.SceneA, to = TestScenes.SceneA)
-
- assertThat(state.isTransitioning()).isFalse()
- assertThat(state.isTransitioning(from = TestScenes.SceneA)).isFalse()
- assertThat(state.isTransitioning(to = TestScenes.SceneB)).isFalse()
- assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB))
- .isFalse()
- }
-
- @Test
fun isTransitioningTo_transition() {
- val state = SceneTransitionLayoutState(TestScenes.SceneA)
- state.transitionState = transition(from = TestScenes.SceneA, to = TestScenes.SceneB)
+ val state = SceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty)
+ state.startTransition(transition(from = TestScenes.SceneA, to = TestScenes.SceneB))
assertThat(state.isTransitioning()).isTrue()
assertThat(state.isTransitioning(from = TestScenes.SceneA)).isTrue()
@@ -64,10 +52,8 @@ class SceneTransitionLayoutStateTest {
}
private fun transition(from: SceneKey, to: SceneKey): TransitionState.Transition {
- return object : TransitionState.Transition {
+ return object : TransitionState.Transition(from, to) {
override val currentScene: SceneKey = from
- override val fromScene: SceneKey = from
- override val toScene: SceneKey = to
override val progress: Float = 0f
override val isInitiatedByUserInput: Boolean = false
override val isUserInputOngoing: Boolean = false
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index fa94b25028a2..ef729921f4cd 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -55,7 +55,7 @@ class TransitionDslTest {
assertThat(transitions.transitionSpecs)
.comparingElementsUsing(
- Correspondence.transforming<TransitionSpec, Pair<SceneKey?, SceneKey?>>(
+ Correspondence.transforming<TransitionSpecImpl, Pair<SceneKey?, SceneKey?>>(
{ it?.from to it?.to },
"has (from, to) equal to"
)
@@ -70,8 +70,8 @@ class TransitionDslTest {
@Test
fun defaultTransitionSpec() {
val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) }
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.spec).isInstanceOf(SpringSpec::class.java)
+ val transformationSpec = transitions.transitionSpecs.single().transformationSpec()
+ assertThat(transformationSpec.progressSpec).isInstanceOf(SpringSpec::class.java)
}
@Test
@@ -79,9 +79,9 @@ class TransitionDslTest {
val transitions = transitions {
from(TestScenes.SceneA, to = TestScenes.SceneB) { spec = tween(durationMillis = 42) }
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.spec).isInstanceOf(TweenSpec::class.java)
- assertThat((transition.spec as TweenSpec).durationMillis).isEqualTo(42)
+ val transformationSpec = transitions.transitionSpecs.single().transformationSpec()
+ assertThat(transformationSpec.progressSpec).isInstanceOf(TweenSpec::class.java)
+ assertThat((transformationSpec.progressSpec as TweenSpec).durationMillis).isEqualTo(42)
}
@Test
@@ -90,9 +90,10 @@ class TransitionDslTest {
from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) }
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations.size).isEqualTo(1)
- assertThat(transition.transformations.single().range).isEqualTo(null)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations.size).isEqualTo(1)
+ assertThat(transformations.single().range).isEqualTo(null)
}
@Test
@@ -105,8 +106,9 @@ class TransitionDslTest {
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 0.1f, end = 0.8f),
@@ -127,8 +129,9 @@ class TransitionDslTest {
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 100 / 500f, end = 300 / 500f),
@@ -149,8 +152,9 @@ class TransitionDslTest {
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
@@ -170,9 +174,13 @@ class TransitionDslTest {
// Fetch the transition from B to A, which will automatically reverse the transition from A
// to B we defined.
- val transition =
- transitions.transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA)
- assertThat(transition.transformations)
+ val transformations =
+ transitions
+ .transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA)
+ .transformationSpec()
+ .transformations
+
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
index 03d231a7fcc6..e2974cddf1b9 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
@@ -17,6 +17,7 @@
package com.android.compose.nestedscroll
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -36,6 +37,15 @@ class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) {
heightRange = heightRange,
)
+ private fun NestedScrollConnection.scroll(
+ available: Offset,
+ consumedByScroll: Offset = Offset.Zero,
+ ) {
+ val consumedByPreScroll = onPreScroll(available = available, source = scrollSource)
+ val consumed = consumedByPreScroll + consumedByScroll
+ onPostScroll(consumed = consumed, available = available - consumed, source = scrollSource)
+ }
+
@Test
fun onScrollUp_consumeHeightFirst() {
val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
@@ -50,6 +60,41 @@ class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) {
}
@Test
+ fun onScrollUpAfterContentScrolled_ignoreUpEvent() {
+ val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+ height = 1f
+
+ // scroll down consumed by a child
+ scrollConnection.scroll(available = Offset(0f, 1f), consumedByScroll = Offset(0f, 1f))
+
+ val offsetConsumed =
+ scrollConnection.onPreScroll(available = Offset(x = 0f, y = -1f), source = scrollSource)
+
+ // It should ignore all onPreScroll events
+ assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+ assertThat(height).isEqualTo(1f)
+ }
+
+ @Test
+ fun onScrollUpAfterContentReturnedToZero_consumeHeight() {
+ val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+ height = 1f
+
+ // scroll down consumed by a child
+ scrollConnection.scroll(available = Offset(0f, 1f), consumedByScroll = Offset(0f, 1f))
+
+ // scroll up consumed by a child, the child is in its original position
+ scrollConnection.scroll(available = Offset(0f, -1f), consumedByScroll = Offset(0f, -1f))
+
+ val offsetConsumed =
+ scrollConnection.onPreScroll(available = Offset(x = 0f, y = -1f), source = scrollSource)
+
+ // It should ignore all onPreScroll events
+ assertThat(offsetConsumed).isEqualTo(Offset(0f, -1f))
+ assertThat(height).isEqualTo(0f)
+ }
+
+ @Test
fun onScrollUp_consumeDownToMin() {
val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
height = 0f
@@ -110,6 +155,27 @@ class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) {
}
@Test
+ fun onScrollDownAfterPostScroll_consumeHeightPreScroll() {
+ val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+ height = 1f
+ scrollConnection.onPostScroll(
+ consumed = Offset.Zero,
+ available = Offset(x = 0f, y = 0.5f),
+ source = scrollSource
+ )
+
+ val offsetConsumed =
+ scrollConnection.onPreScroll(
+ available = Offset(x = 0f, y = 0.5f),
+ source = scrollSource
+ )
+ assertThat(offsetConsumed).isEqualTo(Offset(0f, 0.5f))
+
+ // It can increase by 1 (0.5f + 0.5f) the height
+ assertThat(height).isEqualTo(2f)
+ }
+
+ @Test
fun onScrollDown_consumeUpToMax() {
val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
height = 2f
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
index 122774bb28fe..8a9a92ead89e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
@@ -46,6 +46,7 @@ class PriorityNestedScrollConnectionTest {
canStartPostScroll = { _, _ -> canStartPostScroll },
canStartPostFling = { canStartPostFling },
canContinueScroll = { canContinueScroll },
+ canScrollOnFling = false,
onStart = { isStarted = true },
onScroll = {
lastScroll = it
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 695d888d94f5..f1701356c134 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -18,7 +18,7 @@
package com.android.keyguard
import android.content.res.Configuration
-import android.hardware.biometrics.BiometricOverlayConstants
+import android.hardware.biometrics.BiometricRequestConstants
import android.media.AudioManager
import android.telephony.TelephonyManager
import android.testing.TestableLooper.RunWithLooper
@@ -59,6 +59,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -235,6 +236,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
sceneInteractor = sceneInteractor,
)
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest =
KeyguardSecurityContainerController(
view,
@@ -763,16 +765,18 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
@Test
fun sideFpsControllerShow() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest.updateSideFpsVisibility(/* isVisible= */ true)
verify(sideFpsController)
.show(
SideFpsUiRequestSource.PRIMARY_BOUNCER,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD
)
}
@Test
fun sideFpsControllerHide() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest.updateSideFpsVisibility(/* isVisible= */ false)
verify(sideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt
new file mode 100644
index 000000000000..74f50d8c844b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.accessibility.data.repository
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+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.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionRepositoryImplTest : SysuiTestCase() {
+ companion object {
+ val TEST_USER_1 = UserHandle.of(1)!!
+ val TEST_USER_2 = UserHandle.of(2)!!
+ }
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val scope = TestScope(testDispatcher)
+ private val settings: FakeSettings = FakeSettings()
+
+ private lateinit var underTest: ColorCorrectionRepository
+
+ @Before
+ fun setUp() {
+ underTest =
+ ColorCorrectionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+ }
+
+ @Test
+ fun isEnabled_initiallyGetsSettingsValue() =
+ scope.runTest {
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ 1,
+ TEST_USER_1.identifier
+ )
+
+ underTest =
+ ColorCorrectionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ runCurrent()
+
+ val actualValue: Boolean = underTest.isEnabled(TEST_USER_1).first()
+ Truth.assertThat(actualValue).isTrue()
+ }
+
+ @Test
+ fun isEnabled_settingUpdated_valueUpdated() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.ENABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ }
+
+ @Test
+ fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ underTest.isEnabled(TEST_USER_2).launchIn(backgroundScope)
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_2.identifier
+ )
+
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.ENABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+ }
+
+ @Test
+ fun setEnabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(true, TEST_USER_1)
+ runCurrent()
+ Truth.assertThat(success).isTrue()
+
+ val actualValue =
+ settings.getIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ TEST_USER_1.identifier
+ )
+ Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.ENABLED)
+ }
+
+ @Test
+ fun setDisabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(false, TEST_USER_1)
+ runCurrent()
+ Truth.assertThat(success).isTrue()
+
+ val actualValue =
+ settings.getIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ TEST_USER_1.identifier
+ )
+ Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.DISABLED)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index a1b801cd3d3f..f8321b7e7eb3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -22,9 +22,9 @@ import android.app.ActivityTaskManager
import android.content.ComponentName
import android.graphics.Insets
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_UNKNOWN
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.biometrics.SensorProperties
import android.hardware.display.DisplayManager
@@ -65,6 +65,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -144,6 +145,7 @@ class SideFpsControllerTest : SysuiTestCase() {
@Before
fun setup() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
displayRepository = FakeDisplayRepository()
displayStateRepository = FakeDisplayStateRepository()
keyguardBouncerRepository = FakeKeyguardBouncerRepository()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 90d36e7fd814..a726b7c2b075 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -17,12 +17,12 @@
package com.android.systemui.biometrics
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.RequestReason
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
@@ -135,7 +135,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
}
private fun withReason(
- @ShowReason reason: Int,
+ @RequestReason reason: Int,
isDebuggable: Boolean = false,
enableDeviceEntryUdfpsRefactor: Boolean = false,
block: () -> Unit,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 97ee526b7108..dddcf18c1ede 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -43,7 +43,7 @@ import static org.mockito.Mockito.when;
import android.graphics.Rect;
import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.display.DisplayManager;
@@ -359,7 +359,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void dozeTimeTick() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
mUdfpsController.dozeTimeTick();
verify(mUdfpsView).dozeTimeTick();
@@ -455,7 +455,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
// GIVEN overlay was showing and the udfps bouncer is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
// WHEN the overlay is hidden
@@ -469,7 +469,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void showUdfpsOverlay_callsListener() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mFingerprintManager).onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
@@ -479,7 +479,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong());
@@ -520,7 +520,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
reset(mWindowManager);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID,
mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING,
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING,
mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
@@ -555,7 +555,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Show the overlay.
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
@@ -637,7 +637,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Show the overlay.
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -720,7 +720,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
initUdfpsController(testParams.sensorProps);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
@@ -778,7 +778,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and screen is on and fp is running
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
// WHEN fingerprint is requested because of AOD interrupt
@@ -808,7 +808,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
@@ -886,7 +886,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
@@ -917,7 +917,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
@@ -958,7 +958,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
// Configure UdfpsView to accept the ACTION_UP event
@@ -1019,7 +1019,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN screen off
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOff();
mFgExecutor.runAllReady();
@@ -1041,7 +1041,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN showing overlay
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -1126,7 +1126,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(a11y);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
if (a11y) {
@@ -1148,7 +1148,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -1197,7 +1197,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
-1 /* pointerId */, touchData);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -1289,7 +1289,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
// GIVEN UDFPS overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// GIVEN there's been an AoD interrupt
@@ -1316,7 +1316,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
throws RemoteException {
// GIVEN UDFPS overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// GIVEN there's been an AoD interrupt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 90e0c19b7c65..a3bf3f492e6e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -33,6 +33,7 @@ import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.utils.os.FakeHandler
@@ -105,8 +106,10 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun shouldUpdateSideFps_show() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
var count = 0
val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
repository.setPrimaryShow(true)
@@ -116,8 +119,10 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun shouldUpdateSideFps_hide() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
repository.setPrimaryShow(true)
var count = 0
val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
@@ -128,8 +133,10 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun sideFpsShowing() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
var sideFpsIsShowing = false
val job = underTest.sideFpsShowing.onEach { sideFpsIsShowing = it }.launchIn(this)
repository.setSideFpsShowing(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
index 7196de6608cb..65176e1c5c0d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
@@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
@@ -29,6 +30,8 @@ import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -40,29 +43,30 @@ import org.junit.runner.RunWith
class CommunalRepositoryImplTest : SysuiTestCase() {
private lateinit var underTest: CommunalRepositoryImpl
- private lateinit var testScope: TestScope
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
private lateinit var featureFlagsClassic: FakeFeatureFlagsClassic
- private lateinit var sceneContainerFlags: FakeSceneContainerFlags
private lateinit var sceneContainerRepository: SceneContainerRepository
@Before
fun setUp() {
- testScope = TestScope()
-
val sceneTestUtils = SceneTestUtils(this)
- sceneContainerFlags = FakeSceneContainerFlags(enabled = false)
sceneContainerRepository = sceneTestUtils.fakeSceneContainerRepository()
featureFlagsClassic = FakeFeatureFlagsClassic()
featureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
- underTest =
- CommunalRepositoryImpl(
- featureFlagsClassic,
- sceneContainerFlags,
- sceneContainerRepository,
- )
+ underTest = createRepositoryImpl(false)
+ }
+
+ private fun createRepositoryImpl(sceneContainerEnabled: Boolean): CommunalRepositoryImpl {
+ return CommunalRepositoryImpl(
+ testScope.backgroundScope,
+ featureFlagsClassic,
+ FakeSceneContainerFlags(enabled = sceneContainerEnabled),
+ sceneContainerRepository,
+ )
}
@Test
@@ -86,13 +90,7 @@ class CommunalRepositoryImplTest : SysuiTestCase() {
@Test
fun isCommunalShowing_sceneContainerEnabled_onCommunalScene_true() =
testScope.runTest {
- sceneContainerFlags = FakeSceneContainerFlags(enabled = true)
- underTest =
- CommunalRepositoryImpl(
- featureFlagsClassic,
- sceneContainerFlags,
- sceneContainerRepository,
- )
+ underTest = createRepositoryImpl(true)
sceneContainerRepository.setDesiredScene(SceneModel(key = SceneKey.Communal))
@@ -103,17 +101,49 @@ class CommunalRepositoryImplTest : SysuiTestCase() {
@Test
fun isCommunalShowing_sceneContainerEnabled_onLockscreenScene_false() =
testScope.runTest {
- sceneContainerFlags = FakeSceneContainerFlags(enabled = true)
- underTest =
- CommunalRepositoryImpl(
- featureFlagsClassic,
- sceneContainerFlags,
- sceneContainerRepository,
- )
+ underTest = createRepositoryImpl(true)
sceneContainerRepository.setDesiredScene(SceneModel(key = SceneKey.Lockscreen))
val isCommunalHubShowing by collectLastValue(underTest.isCommunalHubShowing)
assertThat(isCommunalHubShowing).isFalse()
}
+
+ @Test
+ fun transitionState_idleByDefault() =
+ testScope.runTest {
+ val transitionState by collectLastValue(underTest.transitionState)
+ assertThat(transitionState)
+ .isEqualTo(ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT))
+ }
+
+ @Test
+ fun transitionState_setTransitionState_returnsNewValue() =
+ testScope.runTest {
+ val expectedSceneKey = CommunalSceneKey.Communal
+ underTest.setTransitionState(
+ flowOf(ObservableCommunalTransitionState.Idle(expectedSceneKey))
+ )
+
+ val transitionState by collectLastValue(underTest.transitionState)
+ assertThat(transitionState)
+ .isEqualTo(ObservableCommunalTransitionState.Idle(expectedSceneKey))
+ }
+
+ @Test
+ fun transitionState_setNullTransitionState_returnsDefaultValue() =
+ testScope.runTest {
+ // Set a value for the transition state flow.
+ underTest.setTransitionState(
+ flowOf(ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal))
+ )
+
+ // Set the transition state flow back to null.
+ underTest.setTransitionState(null)
+
+ // Flow returns default scene key.
+ val transitionState by collectLastValue(underTest.transitionState)
+ assertThat(transitionState)
+ .isEqualTo(ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT))
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 16cfa2398fd5..1f8e29adc983 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -161,7 +161,7 @@ class CommunalInteractorTest : SysuiTestCase() {
whenever(target1.remoteViews).thenReturn(mock(RemoteViews::class.java))
val targets = listOf(target1, target2, target3)
- smartspaceRepository.setLockscreenSmartspaceTargets(targets)
+ smartspaceRepository.setCommunalSmartspaceTargets(targets)
val smartspaceContent by collectLastValue(underTest.smartspaceContent)
assertThat(smartspaceContent?.size).isEqualTo(1)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 8896e6e64bd9..314dfdfd6f2a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -116,7 +116,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
whenever(target.smartspaceTargetId).thenReturn("target")
whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setLockscreenSmartspaceTargets(listOf(target))
+ smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
// Media playing.
mediaRepository.mediaPlaying.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 7fbcae0d8986..8a71168324aa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -135,7 +135,7 @@ class CommunalViewModelTest : SysuiTestCase() {
whenever(target.smartspaceTargetId).thenReturn("target")
whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setLockscreenSmartspaceTargets(listOf(target))
+ smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
// Media playing.
mediaRepository.mediaPlaying.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 45aca175657e..d6d5b23a311d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -827,7 +827,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
@Test
- fun isAuthenticatedIsResetToFalseWhenKeyguardIsGoingAway() =
+ fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -840,13 +840,13 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
assertThat(authenticated()).isTrue()
- keyguardRepository.setKeyguardGoingAway(true)
+ powerInteractor.setAsleepForTest()
assertThat(authenticated()).isFalse()
}
@Test
- fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() =
+ fun isAuthenticatedIsResetToFalseWhenDeviceGoesToSleep() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -865,7 +865,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
@Test
- fun isAuthenticatedIsResetToFalseWhenDeviceGoesToSleep() =
+ fun isAuthenticatedIsResetToFalseWhenUserIsSwitching() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -878,13 +878,16 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
assertThat(authenticated()).isTrue()
- powerInteractor.setAsleepForTest()
+ fakeUserRepository.setSelectedUserInfo(
+ primaryUser,
+ SelectionStatus.SELECTION_IN_PROGRESS
+ )
assertThat(authenticated()).isFalse()
}
@Test
- fun isAuthenticatedIsResetToFalseWhenUserIsSwitching() =
+ fun isAuthenticatedIsResetToFalseWhenKeyguardDoneAnimationsFinished() =
testScope.runTest {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
@@ -897,10 +900,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
assertThat(authenticated()).isTrue()
- fakeUserRepository.setSelectedUserInfo(
- primaryUser,
- SelectionStatus.SELECTION_IN_PROGRESS
- )
+ keyguardRepository.keyguardDoneAnimationsFinished()
assertThat(authenticated()).isFalse()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index 2b7221ec192c..6b7d2635ffa4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -304,4 +304,34 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
)
assertThat(authenticationStatus).isNull()
}
+
+ @Test
+ fun onBiometricRunningStateChanged_shouldUpdateIndicatorVisibility() =
+ testScope.runTest {
+ val shouldUpdateIndicatorVisibility by
+ collectLastValue(underTest.shouldUpdateIndicatorVisibility)
+ runCurrent()
+
+ verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+ assertThat(shouldUpdateIndicatorVisibility).isFalse()
+
+ invokeOnCallback {
+ it.onBiometricRunningStateChanged(false, BiometricSourceType.FINGERPRINT)
+ }
+ assertThat(shouldUpdateIndicatorVisibility).isTrue()
+ }
+
+ @Test
+ fun onStrongAuthStateChanged_shouldUpdateIndicatorVisibility() =
+ testScope.runTest {
+ val shouldUpdateIndicatorVisibility by
+ collectLastValue(underTest.shouldUpdateIndicatorVisibility)
+ runCurrent()
+
+ verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+ assertThat(shouldUpdateIndicatorVisibility).isFalse()
+
+ invokeOnCallback { it.onStrongAuthStateChanged(0) }
+ assertThat(shouldUpdateIndicatorVisibility).isTrue()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt
new file mode 100644
index 000000000000..e8504563b4ae
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManagerTest.kt
@@ -0,0 +1,40 @@
+package com.android.systemui.keyguard.ui.preview
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class KeyguardRemotePreviewManagerTest : SysuiTestCase() {
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Test
+ fun onDestroy_clearsReferencesToRenderer() =
+ testScope.runTest {
+ val renderer = mock<KeyguardPreviewRenderer>()
+ val onDestroy: (PreviewLifecycleObserver) -> Unit = {}
+
+ val observer = PreviewLifecycleObserver(this, testDispatcher, renderer, onDestroy)
+
+ // Precondition check.
+ assertThat(observer.renderer).isNotNull()
+ assertThat(observer.onDestroy).isNotNull()
+
+ observer.onDestroy()
+
+ // The verification checks renderer/requestDestruction lambda because they-re
+ // non-singletons which can't leak KeyguardPreviewRenderer.
+ assertThat(observer.renderer).isNull()
+ assertThat(observer.onDestroy).isNull()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS
new file mode 100644
index 000000000000..cd04e82d7816
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include /packages/SystemUI/src/com/android/systemui/qs/OWNERS
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
new file mode 100644
index 000000000000..30d1822b28da
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.qs.pipeline.data.restoreprocessors
+
+import android.os.UserHandle
+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.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class WorkTileRestoreProcessorTest : SysuiTestCase() {
+
+ private val underTest = WorkTileRestoreProcessor()
+ @Test
+ fun restoreWithWorkTile_removeTracking() = runTest {
+ val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER)))
+ runCurrent()
+
+ val restoreData =
+ RestoreData(
+ restoredTiles = listOf(TILE_SPEC),
+ restoredAutoAddedTiles = setOf(TILE_SPEC),
+ USER,
+ )
+
+ underTest.postProcessRestore(restoreData)
+
+ assertThat(removeTracking).isEqualTo(Unit)
+ }
+
+ @Test
+ fun restoreWithWorkTile_otherUser_noRemoveTracking() = runTest {
+ val removeTracking by
+ collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER + 1)))
+ runCurrent()
+
+ val restoreData =
+ RestoreData(
+ restoredTiles = listOf(TILE_SPEC),
+ restoredAutoAddedTiles = setOf(TILE_SPEC),
+ USER,
+ )
+
+ underTest.postProcessRestore(restoreData)
+
+ assertThat(removeTracking).isNull()
+ }
+
+ @Test
+ fun restoreWithoutWorkTile_noSignal() = runTest {
+ val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER)))
+ runCurrent()
+
+ val restoreData =
+ RestoreData(
+ restoredTiles = emptyList(),
+ restoredAutoAddedTiles = emptySet(),
+ USER,
+ )
+
+ underTest.postProcessRestore(restoreData)
+
+ assertThat(removeTracking).isNull()
+ }
+
+ companion object {
+ private const val USER = 10
+ private val TILE_SPEC = TileSpec.Companion.create("work")
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
index adccc84e494b..c7e7845f206c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
@@ -25,6 +25,11 @@ 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.coroutines.collectValues
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
+import com.android.systemui.qs.pipeline.data.model.workTileRestoreProcessor
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -32,25 +37,28 @@ import com.android.systemui.qs.tiles.WorkModeTile
import com.android.systemui.settings.FakeUserTracker
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.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class WorkTileAutoAddableTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+
+ private val restoreProcessor: RestoreProcessor
+ get() = kosmos.workTileRestoreProcessor
+
private lateinit var userTracker: FakeUserTracker
private lateinit var underTest: WorkTileAutoAddable
@Before
fun setup() {
- MockitoAnnotations.initMocks(this)
-
userTracker =
FakeUserTracker(
_userId = USER_INFO_0.id,
@@ -58,7 +66,7 @@ class WorkTileAutoAddableTest : SysuiTestCase() {
_userProfiles = listOf(USER_INFO_0)
)
- underTest = WorkTileAutoAddable(userTracker)
+ underTest = WorkTileAutoAddable(userTracker, kosmos.workTileRestoreProcessor)
}
@Test
@@ -114,10 +122,80 @@ class WorkTileAutoAddableTest : SysuiTestCase() {
assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
}
+ @Test
+ fun restoreDataWithWorkTile_noCurrentManagedProfile_triggersRemove() = runTest {
+ val userId = 0
+ val signal by collectLastValue(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signal!!).isEqualTo(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
+ @Test
+ fun restoreDataWithWorkTile_currentlyManagedProfile_doesntTriggerRemove() = runTest {
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+ val userId = 0
+ val signals by collectValues(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
+ @Test
+ fun restoreDataWithoutWorkTile_noManagedProfile_doesntTriggerRemove() = runTest {
+ val userId = 0
+ val signals by collectValues(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithoutWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
+ @Test
+ fun restoreDataWithoutWorkTile_managedProfile_doesntTriggerRemove() = runTest {
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+ val userId = 0
+ val signals by collectValues(underTest.autoAddSignal(userId))
+ runCurrent()
+
+ val restoreData = createRestoreWithoutWorkTile(userId)
+
+ restoreProcessor.postProcessRestore(restoreData)
+
+ assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC))
+ }
+
companion object {
private val SPEC = TileSpec.create(WorkModeTile.TILE_SPEC)
private val USER_INFO_0 = UserInfo(0, "", FLAG_PRIMARY or FLAG_FULL)
private val USER_INFO_1 = UserInfo(1, "", FLAG_FULL)
private val USER_INFO_WORK = UserInfo(10, "", FLAG_PROFILE or FLAG_MANAGED_PROFILE)
+
+ private fun createRestoreWithWorkTile(userId: Int): RestoreData {
+ return RestoreData(
+ listOf(TileSpec.create("a"), SPEC, TileSpec.create("b")),
+ setOf(SPEC),
+ userId,
+ )
+ }
+
+ private fun createRestoreWithoutWorkTile(userId: Int): RestoreData {
+ return RestoreData(
+ listOf(TileSpec.create("a"), TileSpec.create("b")),
+ emptySet(),
+ userId,
+ )
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
index 41a7ec03408d..54b03a90229b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
@@ -183,6 +183,22 @@ class AutoAddInteractorTest : SysuiTestCase() {
assertThat(autoAddedTiles).contains(SPEC)
}
+ @Test
+ fun autoAddable_removeTrackingSignal_notRemovedButUnmarked() =
+ testScope.runTest {
+ autoAddRepository.markTileAdded(USER, SPEC)
+ val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ fakeAutoAddable.sendRemoveTrackingSignal(USER)
+ runCurrent()
+
+ verify(currentTilesInteractor, never()).removeTiles(any())
+ assertThat(autoAddedTiles).doesNotContain(SPEC)
+ }
+
private fun createInteractor(autoAddables: Set<AutoAddable>): AutoAddInteractor {
return AutoAddInteractor(
autoAddables,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
index f73cab8a10a3..b2a9783d2e60 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
@@ -5,10 +5,15 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
import com.android.systemui.qs.pipeline.data.repository.FakeAutoAddRepository
import com.android.systemui.qs.pipeline.data.repository.FakeQSSettingsRestoredRepository
import com.android.systemui.qs.pipeline.data.repository.FakeTileSpecRepository
import com.android.systemui.qs.pipeline.data.repository.TilesSettingConverter
+import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.POSTPROCESS
+import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.PREPROCESS
+import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -17,7 +22,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.inOrder
@RunWith(AndroidJUnit4::class)
@SmallTest
@@ -28,6 +33,9 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() {
private val qsSettingsRestoredRepository = FakeQSSettingsRestoredRepository()
+ private val restoreProcessor: TestableRestoreProcessor = TestableRestoreProcessor()
+ private val qsLogger: QSPipelineLogger = mock()
+
private lateinit var underTest: RestoreReconciliationInteractor
private val testDispatcher = StandardTestDispatcher()
@@ -35,13 +43,13 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() {
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
underTest =
RestoreReconciliationInteractor(
tileSpecRepository,
autoAddRepository,
qsSettingsRestoredRepository,
+ setOf(restoreProcessor),
+ qsLogger,
testScope.backgroundScope,
testDispatcher
)
@@ -85,6 +93,44 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() {
assertThat(autoAdd).isEqualTo(expectedAutoAdd.toTilesSet())
}
+ @Test
+ fun restoreProcessorsCalled() =
+ testScope.runTest {
+ val user = 10
+
+ val restoredSpecs = "a,c,d,f"
+ val restoredAutoAdded = "d,e"
+
+ val restoreData =
+ RestoreData(
+ restoredSpecs.toTilesList(),
+ restoredAutoAdded.toTilesSet(),
+ user,
+ )
+
+ qsSettingsRestoredRepository.onDataRestored(restoreData)
+ runCurrent()
+
+ assertThat(restoreProcessor.calls).containsExactly(PREPROCESS, POSTPROCESS).inOrder()
+ }
+
+ private class TestableRestoreProcessor : RestoreProcessor {
+ val calls = mutableListOf<Any>()
+
+ override suspend fun preProcessRestore(restoreData: RestoreData) {
+ calls.add(PREPROCESS)
+ }
+
+ override suspend fun postProcessRestore(restoreData: RestoreData) {
+ calls.add(POSTPROCESS)
+ }
+
+ companion object {
+ val PREPROCESS = Any()
+ val POSTPROCESS = Any()
+ }
+ }
+
companion object {
private fun String.toTilesList() = TilesSettingConverter.toTilesList(this)
private fun String.toTilesSet() = TilesSettingConverter.toTilesSet(this)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt
new file mode 100644
index 000000000000..96d57743e2ee
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.qs.pipeline.domain.interactor
+
+import android.content.pm.UserInfo
+import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.android.systemui.Flags.FLAG_QS_NEW_PIPELINE
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.FakeQSFactory
+import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.repository.fakeRestoreRepository
+import com.android.systemui.qs.pipeline.data.repository.fakeTileSpecRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.qsTileFactory
+import com.android.systemui.settings.fakeUserTracker
+import com.android.systemui.settings.userTracker
+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
+
+/**
+ * This integration test is for testing the solution to b/314781280. In particular, there are two
+ * issues we want to verify after a restore of a device with a work profile and a work mode tile:
+ * * When the work profile is re-enabled in the target device, it is auto-added.
+ * * The tile is auto-added in the same position that it was in the restored device.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class WorkProfileAutoAddedAfterRestoreTest : SysuiTestCase() {
+
+ private val kosmos = Kosmos().apply { fakeUserTracker.set(listOf(USER_0_INFO), 0) }
+ // Getter here so it can change when there is a managed profile.
+ private val workTileAvailable: Boolean
+ get() = hasManagedProfile()
+ private val currentUser: Int
+ get() = kosmos.userTracker.userId
+
+ private val testScope: TestScope
+ get() = kosmos.testScope
+
+ @Before
+ fun setUp() {
+ mSetFlagsRule.enableFlags(FLAG_QS_NEW_PIPELINE)
+
+ kosmos.qsTileFactory = FakeQSFactory(::tileCreator)
+ kosmos.restoreReconciliationInteractor.start()
+ kosmos.autoAddInteractor.init(kosmos.currentTilesInteractor)
+ }
+
+ @Test
+ fun workTileRestoredAndPreviouslyAutoAdded_notAvailable_willBeAutoaddedInCorrectPosition() =
+ testScope.runTest {
+ val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles)
+
+ // Set up
+ val currentTiles = listOf("a".toTileSpec())
+ kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles)
+
+ val restoredTiles =
+ listOf(WORK_TILE_SPEC) + listOf("b", "c", "d").map { it.toTileSpec() }
+ val restoredAutoAdded = setOf(WORK_TILE_SPEC)
+
+ val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser)
+
+ // WHEN we restore tiles that auto-added the WORK tile and it's not available (there
+ // are no managed profiles)
+ kosmos.fakeRestoreRepository.onDataRestored(restoreData)
+
+ // THEN the work tile is not part of the current tiles
+ assertThat(tiles!!).hasSize(3)
+ assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC)
+
+ // WHEN we add a work profile
+ createManagedProfileAndAdd()
+
+ // THEN the work profile is added in the correct place
+ assertThat(tiles!!.first().spec).isEqualTo(WORK_TILE_SPEC)
+ }
+
+ @Test
+ fun workTileNotRestoredAndPreviouslyAutoAdded_wontBeAutoAddedWhenWorkProfileIsAdded() =
+ testScope.runTest {
+ val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles)
+
+ // Set up
+ val currentTiles = listOf("a".toTileSpec())
+ kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles)
+ runCurrent()
+
+ val restoredTiles = listOf("b", "c", "d").map { it.toTileSpec() }
+ val restoredAutoAdded = setOf(WORK_TILE_SPEC)
+
+ val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser)
+
+ // WHEN we restore tiles that auto-added the WORK tile
+ kosmos.fakeRestoreRepository.onDataRestored(restoreData)
+
+ // THEN the work tile is not part of the current tiles
+ assertThat(tiles!!).hasSize(3)
+ assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC)
+
+ // WHEN we add a work profile
+ createManagedProfileAndAdd()
+
+ // THEN the work profile is not added because the user had manually removed it in the
+ // past
+ assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC)
+ }
+
+ private fun tileCreator(spec: String): QSTile {
+ return if (spec == WORK_TILE_SPEC.spec) {
+ FakeQSTile(currentUser, workTileAvailable)
+ } else {
+ FakeQSTile(currentUser)
+ }
+ }
+
+ private fun hasManagedProfile(): Boolean {
+ return kosmos.userTracker.userProfiles.any { it.isManagedProfile }
+ }
+
+ private fun TestScope.createManagedProfileAndAdd() {
+ kosmos.fakeUserTracker.set(
+ listOf(USER_0_INFO, MANAGED_USER_INFO),
+ 0,
+ )
+ runCurrent()
+ }
+
+ private companion object {
+ val WORK_TILE_SPEC = "work".toTileSpec()
+ val USER_0_INFO =
+ UserInfo(
+ 0,
+ "zero",
+ "",
+ UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+ )
+ val MANAGED_USER_INFO =
+ UserInfo(
+ 10,
+ "ten-managed",
+ "",
+ 0,
+ UserManager.USER_TYPE_PROFILE_MANAGED,
+ )
+
+ fun String.toTileSpec() = TileSpec.create(this)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
index 2b744ac8398a..00405d0a07e7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.alarm.domain
import android.app.AlarmManager
+import android.graphics.drawable.TestStubDrawable
import android.widget.Switch
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -40,7 +41,14 @@ class AlarmTileMapperTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val alarmTileConfig = kosmos.qsAlarmTileConfig
// Using lazy (versus =) to make sure we override the right context -- see b/311612168
- private val mapper by lazy { AlarmTileMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ AlarmTileMapper(
+ context.orCreateTestableResources
+ .apply { addOverride(R.drawable.ic_alarm, TestStubDrawable()) }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun notAlarmSet() {
@@ -100,7 +108,7 @@ class AlarmTileMapperTest : SysuiTestCase() {
): QSTileState {
val label = context.getString(R.string.status_bar_alarm)
return QSTileState(
- { Icon.Resource(R.drawable.ic_alarm, null) },
+ { Icon.Loaded(context.getDrawable(R.drawable.ic_alarm)!!, null) },
label,
activationState,
secondaryLabel,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt
new file mode 100644
index 000000000000..8ee6d2005350
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain
+
+import android.graphics.drawable.TestStubDrawable
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.impl.colorcorrection.qsColorCorrectionTileConfig
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val colorCorrectionTileConfig = kosmos.qsColorCorrectionTileConfig
+ private val subtitleArray =
+ context.resources.getStringArray(R.array.tile_states_color_correction)
+ // Using lazy (versus =) to make sure we override the right context -- see b/311612168
+ private val mapper by lazy {
+ ColorCorrectionTileMapper(
+ context.orCreateTestableResources
+ .apply { addOverride(R.drawable.ic_qs_color_correction, TestStubDrawable()) }
+ .resources,
+ context.theme
+ )
+ }
+
+ @Test
+ fun disabledModel() {
+ val inputModel = ColorCorrectionTileModel(false)
+
+ val outputState = mapper.map(colorCorrectionTileConfig, inputModel)
+
+ val expectedState =
+ createColorCorrectionTileState(QSTileState.ActivationState.INACTIVE, subtitleArray[1])
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun enabledModel() {
+ val inputModel = ColorCorrectionTileModel(true)
+
+ val outputState = mapper.map(colorCorrectionTileConfig, inputModel)
+
+ val expectedState =
+ createColorCorrectionTileState(QSTileState.ActivationState.ACTIVE, subtitleArray[2])
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ private fun createColorCorrectionTileState(
+ activationState: QSTileState.ActivationState,
+ secondaryLabel: String
+ ): QSTileState {
+ val label = context.getString(R.string.quick_settings_color_correction_label)
+ return QSTileState(
+ { Icon.Loaded(context.getDrawable(R.drawable.ic_qs_color_correction)!!, null) },
+ label,
+ activationState,
+ secondaryLabel,
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
+ label,
+ null,
+ QSTileState.SideViewIcon.None,
+ QSTileState.EnabledState.ENABLED,
+ Switch::class.qualifiedName
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
new file mode 100644
index 000000000000..8c612acad887
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toCollection
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileDataInteractorTest : SysuiTestCase() {
+
+ private val colorCorrectionRepository = FakeColorCorrectionRepository()
+ private val underTest: ColorCorrectionTileDataInteractor =
+ ColorCorrectionTileDataInteractor(colorCorrectionRepository)
+
+ @Test
+ fun alwaysAvailable() = runTest {
+ val availability = underTest.availability(TEST_USER).toCollection(mutableListOf())
+
+ assertThat(availability).hasSize(1)
+ assertThat(availability.last()).isTrue()
+ }
+
+ @Test
+ fun dataMatchesTheRepository() = runTest {
+ val dataList: List<ColorCorrectionTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+ runCurrent()
+
+ colorCorrectionRepository.setIsEnabled(true, TEST_USER)
+ runCurrent()
+
+ colorCorrectionRepository.setIsEnabled(false, TEST_USER)
+ runCurrent()
+
+ assertThat(dataList).hasSize(3)
+ assertThat(dataList.map { it.isEnabled }).isEqualTo(listOf(false, true, false))
+ }
+
+ private companion object {
+ val TEST_USER = UserHandle.of(1)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
new file mode 100644
index 000000000000..3049cc079a1c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() {
+
+ private val testUser = UserHandle.CURRENT
+ private val repository = FakeColorCorrectionRepository()
+ private val inputHandler = FakeQSTileIntentUserInputHandler()
+
+ private val underTest =
+ ColorCorrectionUserActionInteractor(
+ repository,
+ inputHandler,
+ )
+
+ @Test
+ fun handleClickWhenEnabled() = runTest {
+ val wasEnabled = true
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorCorrectionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleClickWhenDisabled() = runTest {
+ val wasEnabled = false
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorCorrectionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleLongClickWhenDisabled() = runTest {
+ val enabled = false
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorCorrectionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ }
+ }
+
+ @Test
+ fun handleLongClickWhenEnabled() = runTest {
+ val enabled = true
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorCorrectionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt
index 4a221134ce67..2eeb75e3443b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/CustomTilePackageUpdatesRepositoryTest.kt
@@ -16,23 +16,27 @@
package com.android.systemui.qs.tiles.impl.custom
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.qs.external.TileLifecycleManager
-import com.android.systemui.qs.external.TileServiceManager
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTilePackageUpdatesRepository
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTilePackageUpdatesRepositoryImpl
-import com.android.systemui.qs.tiles.impl.custom.data.repository.FakeCustomTileDefaultsRepository
-import com.android.systemui.qs.tiles.impl.custom.data.repository.FakeCustomTileDefaultsRepository.DefaultsRequest
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -49,14 +53,12 @@ import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
+@SuppressLint("UnspecifiedRegisterReceiverFlag") // Not needed in the test
class CustomTilePackageUpdatesRepositoryTest : SysuiTestCase() {
- @Mock private lateinit var tileServiceManager: TileServiceManager
+ @Mock private lateinit var mockedContext: Context
+ @Captor private lateinit var listenerCaptor: ArgumentCaptor<BroadcastReceiver>
- @Captor
- private lateinit var listenerCaptor: ArgumentCaptor<TileLifecycleManager.TileChangeListener>
-
- private val defaultsRepository = FakeCustomTileDefaultsRepository()
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -69,37 +71,29 @@ class CustomTilePackageUpdatesRepositoryTest : SysuiTestCase() {
underTest =
CustomTilePackageUpdatesRepositoryImpl(
TileSpec.create(COMPONENT_1),
- USER,
- tileServiceManager,
- defaultsRepository,
+ mockedContext,
testScope.backgroundScope,
+ testDispatcher,
)
}
@Test
- fun packageChangesUpdatesDefaults() =
+ fun packageChangesEmittedForTilePassing() =
testScope.runTest {
- val events = mutableListOf<Unit>()
- underTest.packageChanges.onEach { events.add(it) }.launchIn(backgroundScope)
+ val events by collectValues(underTest.getPackageChangesForUser(USER_1))
runCurrent()
- verify(tileServiceManager).setTileChangeListener(capture(listenerCaptor))
- emitPackageChange()
+ emitPackageChange(COMPONENT_1)
runCurrent()
assertThat(events).hasSize(1)
- assertThat(defaultsRepository.defaultsRequests).isNotEmpty()
- assertThat(defaultsRepository.defaultsRequests.last())
- .isEqualTo(DefaultsRequest(USER, COMPONENT_1, true))
}
@Test
- fun packageChangesEmittedOnlyForTheTile() =
+ fun packageChangesEmittedForAnotherTileIgnored() =
testScope.runTest {
- val events = mutableListOf<Unit>()
- underTest.packageChanges.onEach { events.add(it) }.launchIn(backgroundScope)
+ val events by collectValues(underTest.getPackageChangesForUser(USER_1))
runCurrent()
- verify(tileServiceManager).setTileChangeListener(capture(listenerCaptor))
emitPackageChange(COMPONENT_2)
runCurrent()
@@ -107,12 +101,60 @@ class CustomTilePackageUpdatesRepositoryTest : SysuiTestCase() {
assertThat(events).isEmpty()
}
- private fun emitPackageChange(componentName: ComponentName = COMPONENT_1) {
- listenerCaptor.value.onTileChanged(componentName)
+ @Test
+ fun unsupportedActionDoesntEmmit() =
+ testScope.runTest {
+ val events by collectValues(underTest.getPackageChangesForUser(USER_1))
+ runCurrent()
+
+ verify(mockedContext)
+ .registerReceiverAsUser(
+ capture(listenerCaptor),
+ any(),
+ any(),
+ nullable(),
+ nullable()
+ )
+ listenerCaptor.value.onReceive(mockedContext, Intent(Intent.ACTION_MAIN))
+ runCurrent()
+
+ assertThat(events).isEmpty()
+ }
+
+ @Test
+ fun cachesCallsPerUser() =
+ testScope.runTest {
+ underTest.getPackageChangesForUser(USER_1).launchIn(backgroundScope)
+ underTest.getPackageChangesForUser(USER_1).launchIn(backgroundScope)
+ underTest.getPackageChangesForUser(USER_2).launchIn(backgroundScope)
+ underTest.getPackageChangesForUser(USER_2).launchIn(backgroundScope)
+ runCurrent()
+
+ // Register receiver once per each user
+ verify(mockedContext)
+ .registerReceiverAsUser(any(), eq(USER_1), any(), nullable(), nullable())
+ verify(mockedContext)
+ .registerReceiverAsUser(any(), eq(USER_2), any(), nullable(), nullable())
+ }
+
+ private fun emitPackageChange(componentName: ComponentName) {
+ verify(mockedContext)
+ .registerReceiverAsUser(capture(listenerCaptor), any(), any(), nullable(), nullable())
+ listenerCaptor.value.onReceive(
+ mockedContext,
+ Intent(Intent.ACTION_PACKAGE_CHANGED).apply {
+ type = IntentFilter.SCHEME_PACKAGE
+ putExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
+ arrayOf(componentName.packageName)
+ )
+ }
+ )
}
private companion object {
- val USER = UserHandle(0)
+ val USER_1 = UserHandle(1)
+ val USER_2 = UserHandle(2)
val COMPONENT_1 = ComponentName("pkg.test.1", "cls.test")
val COMPONENT_2 = ComponentName("pkg.test.2", "cls.test")
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt
index 7b2ac90b9766..b60f483cccbb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.flashlight.domain
+import android.graphics.drawable.TestStubDrawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,7 +36,17 @@ import org.junit.runner.RunWith
class FlashlightMapperTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val qsTileConfig = kosmos.qsFlashlightTileConfig
- private val mapper by lazy { FlashlightMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ FlashlightMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_flashlight_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_flashlight_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun mapsDisabledDataToInactiveState() {
@@ -56,20 +67,20 @@ class FlashlightMapperTest : SysuiTestCase() {
@Test
fun mapsEnabledDataToOnIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_flashlight_icon_on, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(true))
+ val expectedIcon =
+ Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, null)
val actualIcon = tileState.icon()
assertThat(actualIcon).isEqualTo(expectedIcon)
}
@Test
fun mapsDisabledDataToOffIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_flashlight_icon_off, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(false))
+ val expectedIcon =
+ Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null)
val actualIcon = tileState.icon()
assertThat(actualIcon).isEqualTo(expectedIcon)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt
index 8791877f8863..ea74a4c0d398 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.location.domain
+import android.graphics.drawable.TestStubDrawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -36,7 +37,17 @@ class LocationTileMapperTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val qsTileConfig = kosmos.qsLocationTileConfig
- private val mapper by lazy { LocationTileMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ LocationTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_location_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_location_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun mapsDisabledDataToInactiveState() {
@@ -56,20 +67,18 @@ class LocationTileMapperTest : SysuiTestCase() {
@Test
fun mapsEnabledDataToOnIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_location_icon_on, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, LocationTileModel(true))
+ val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_location_icon_on)!!, null)
val actualIcon = tileState.icon()
Truth.assertThat(actualIcon).isEqualTo(expectedIcon)
}
@Test
fun mapsDisabledDataToOffIconState() {
- val expectedIcon = Icon.Resource(R.drawable.qs_location_icon_off, null)
-
val tileState: QSTileState = mapper.map(qsTileConfig, LocationTileModel(false))
+ val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_location_icon_off)!!, null)
val actualIcon = tileState.icon()
Truth.assertThat(actualIcon).isEqualTo(expectedIcon)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt
index d1824129590b..d162c778f607 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.saver.domain
+import android.graphics.drawable.TestStubDrawable
import android.widget.Switch
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -37,7 +38,17 @@ class DataSaverTileMapperTest : SysuiTestCase() {
private val dataSaverTileConfig = kosmos.qsDataSaverTileConfig
// Using lazy (versus =) to make sure we override the right context -- see b/311612168
- private val mapper by lazy { DataSaverTileMapper(context.orCreateTestableResources.resources) }
+ private val mapper by lazy {
+ DataSaverTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_data_saver_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_data_saver_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
+ }
@Test
fun activeStateMatchesEnabledModel() {
@@ -80,7 +91,7 @@ class DataSaverTileMapperTest : SysuiTestCase() {
else context.resources.getStringArray(R.array.tile_states_saver)[0]
return QSTileState(
- { Icon.Resource(iconRes, null) },
+ { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
label,
activationState,
secondaryLabel,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
index 87f50090e58b..a9776068b20c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.uimodenight.domain
import android.app.UiModeManager
+import android.graphics.drawable.TestStubDrawable
import android.text.TextUtils
import android.view.View
import android.widget.Switch
@@ -41,7 +42,15 @@ class UiModeNightTileMapperTest : SysuiTestCase() {
private val qsTileConfig = kosmos.qsUiModeNightTileConfig
private val mapper by lazy {
- UiModeNightTileMapper(context.orCreateTestableResources.resources)
+ UiModeNightTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_light_dark_theme_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_light_dark_theme_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
}
private fun createUiNightModeTileState(
@@ -60,7 +69,7 @@ class UiModeNightTileMapperTest : SysuiTestCase() {
expandedAccessibilityClass: KClass<out View>? = Switch::class,
): QSTileState {
return QSTileState(
- { Icon.Resource(iconRes, null) },
+ { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
label,
activationState,
secondaryLabel,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
new file mode 100644
index 000000000000..ef2046d85a14
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
@@ -0,0 +1,172 @@
+/*
+ * 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.smartspace
+
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.app.smartspace.SmartspaceTarget
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.testing.TestableLooper
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.smartspace.CommunalSmartspaceController
+import com.android.systemui.plugins.BcSmartspaceConfigPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.util.concurrency.Execution
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class CommunalSmartspaceControllerTest : SysuiTestCase() {
+ @Mock private lateinit var smartspaceManager: SmartspaceManager
+
+ @Mock private lateinit var execution: Execution
+
+ @Mock private lateinit var uiExecutor: Executor
+
+ @Mock private lateinit var targetFilter: SmartspaceTargetFilter
+
+ @Mock private lateinit var plugin: BcSmartspaceDataPlugin
+
+ @Mock private lateinit var precondition: SmartspacePrecondition
+
+ @Mock private lateinit var listener: BcSmartspaceDataPlugin.SmartspaceTargetListener
+
+ @Mock private lateinit var session: SmartspaceSession
+
+ private lateinit var controller: CommunalSmartspaceController
+
+ // TODO(b/272811280): Remove usage of real view
+ private val fakeParent = FrameLayout(context)
+
+ /**
+ * A class which implements SmartspaceView and extends View. This is mocked to provide the right
+ * object inheritance and interface implementation used in CommunalSmartspaceController
+ */
+ private class TestView(context: Context?) : View(context), SmartspaceView {
+ override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {}
+
+ override fun registerConfigProvider(plugin: BcSmartspaceConfigPlugin?) {}
+
+ override fun setPrimaryTextColor(color: Int) {}
+
+ override fun setUiSurface(uiSurface: String) {}
+
+ override fun setDozeAmount(amount: Float) {}
+
+ override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) {}
+
+ override fun setFalsingManager(falsingManager: FalsingManager?) {}
+
+ override fun setDnd(image: Drawable?, description: String?) {}
+
+ override fun setNextAlarm(image: Drawable?, description: String?) {}
+
+ override fun setMediaTarget(target: SmartspaceTarget?) {}
+
+ override fun getSelectedPage(): Int {
+ return 0
+ }
+
+ override fun getCurrentCardTopPadding(): Int {
+ return 0
+ }
+ }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(session)
+
+ controller =
+ CommunalSmartspaceController(
+ context,
+ smartspaceManager,
+ execution,
+ uiExecutor,
+ precondition,
+ Optional.of(targetFilter),
+ Optional.of(plugin)
+ )
+ }
+
+ /** Ensures smartspace session begins on a listener only flow. */
+ @Test
+ fun testConnectOnListen() {
+ `when`(precondition.conditionsMet()).thenReturn(true)
+ controller.addListener(listener)
+
+ verify(smartspaceManager).createSmartspaceSession(any())
+
+ var targetListener =
+ withArgCaptor<SmartspaceSession.OnTargetsAvailableListener> {
+ verify(session).addOnTargetsAvailableListener(any(), capture())
+ }
+
+ `when`(targetFilter.filterSmartspaceTarget(any())).thenReturn(true)
+
+ var target = Mockito.mock(SmartspaceTarget::class.java)
+ targetListener.onTargetsAvailable(listOf(target))
+
+ var targets =
+ withArgCaptor<List<SmartspaceTarget>> { verify(plugin).onTargetsAvailable(capture()) }
+
+ assertThat(targets.contains(target)).isTrue()
+
+ controller.removeListener(listener)
+
+ verify(session).close()
+ }
+
+ /**
+ * Ensures session is closed and weather plugin unregisters the notifier when weather smartspace
+ * view is detached.
+ */
+ @Test
+ fun testDisconnect_emitsEmptyListAndRemovesNotifier() {
+ `when`(precondition.conditionsMet()).thenReturn(true)
+ controller.addListener(listener)
+
+ verify(smartspaceManager).createSmartspaceSession(any())
+
+ controller.removeListener(listener)
+
+ verify(session).close()
+
+ // And the listener receives an empty list of targets and unregisters the notifier
+ verify(plugin).onTargetsAvailable(emptyList())
+ verify(plugin).registerSmartspaceEventNotifier(null)
+ }
+}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 64c0f99f4ba7..c99cb39f91bf 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -44,6 +44,7 @@ public interface BcSmartspaceDataPlugin extends Plugin {
String UI_SURFACE_HOME_SCREEN = "home";
String UI_SURFACE_MEDIA = "media_data_manager";
String UI_SURFACE_DREAM = "dream";
+ String UI_SURFACE_GLANCEABLE_HUB = "glanceable_hub";
String ACTION = "com.android.systemui.action.PLUGIN_BC_SMARTSPACE_DATA";
int VERSION = 1;
diff --git a/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml
deleted file mode 100644
index 02e10cd4ad7c..000000000000
--- a/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true">
- <shape android:shape="rectangle">
- <corners android:radius="16dp" />
- <stroke android:width="3dp"
- android:color="@color/bouncer_password_focus_color" />
- </shape>
- </item>
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
index 0b35559148af..66c54f2a668e 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
@@ -23,7 +23,7 @@
android:layout_marginTop="@dimen/keyguard_lock_padding"
android:importantForAccessibility="no"
android:ellipsize="marquee"
- android:focusable="false"
+ android:focusable="true"
android:gravity="center"
android:singleLine="true" />
</merge>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
index 48769fdebd99..073f090027ba 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
@@ -18,8 +18,6 @@
<TextView
android:id="@+id/digit_text"
style="@style/Widget.TextView.NumPadKey.Digit"
- android:autoSizeMaxTextSize="32sp"
- android:autoSizeTextType="uniform"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 6e6709f94abb..2cca9510417a 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -69,14 +69,13 @@
<item name="android:singleLine">true</item>
<item name="android:gravity">center_horizontal|center_vertical</item>
<item name="android:background">@null</item>
- <item name="android:textSize">32sp</item>
+ <item name="android:textSize">32dp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:paddingBottom">-16dp</item>
</style>
<style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:background">@drawable/bouncer_password_text_view_focused_background</item>
<item name="android:gravity">center</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
diff --git a/packages/SystemUI/res/drawable/arrow_pointing_down.xml b/packages/SystemUI/res/drawable/arrow_pointing_down.xml
new file mode 100644
index 000000000000..be39683cd78d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/arrow_pointing_down.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5.41,7.59L4,9l8,8 8,-8 -1.41,-1.41L12,14.17" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/record_issue_dialog.xml b/packages/SystemUI/res/layout/record_issue_dialog.xml
new file mode 100644
index 000000000000..53ad9f157a2e
--- /dev/null
+++ b/packages/SystemUI/res/layout/record_issue_dialog.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ android:text="@string/qs_record_issue_dropdown_header" />
+
+ <Button
+ android:id="@+id/issue_type_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/qs_record_issue_dropdown_prompt"
+ android:lines="1"
+ android:drawableRight="@drawable/arrow_pointing_down"
+ android:layout_marginTop="@dimen/qqs_layout_margin_top"
+ android:focusable="false"
+ android:clickable="true" />
+
+ <!-- Screen Record Switch -->
+ <LinearLayout
+ android:id="@+id/screenrecord_switch_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/qqs_layout_margin_top"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/screenrecord_option_icon_size"
+ android:layout_height="@dimen/screenrecord_option_icon_size"
+ android:layout_weight="0"
+ android:src="@drawable/ic_screenrecord"
+ app:tint="?androidprv:attr/materialColorOnSurface"
+ android:layout_gravity="center"
+ android:layout_marginEnd="@dimen/screenrecord_option_padding" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/screenrecord_option_icon_size"
+ android:layout_weight="1"
+ android:layout_gravity="fill_vertical"
+ android:gravity="center"
+ android:text="@string/quick_settings_screen_record_label"
+ android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ android:importantForAccessibility="no"/>
+
+ <Switch
+ android:id="@+id/screenrecord_switch"
+ android:layout_width="wrap_content"
+ android:minHeight="@dimen/screenrecord_option_icon_size"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="fill_vertical"
+ android:layout_weight="0"
+ android:contentDescription="@string/quick_settings_screen_record_label" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/sidefps_view.xml b/packages/SystemUI/res/layout/sidefps_view.xml
index 4d952209da6f..fc4bf8a65643 100644
--- a/packages/SystemUI/res/layout/sidefps_view.xml
+++ b/packages/SystemUI/res/layout/sidefps_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.SideFpsLottieViewWrapper
+<com.android.systemui.biometrics.SideFpsIndicatorView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sidefps_animation"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index a22fd18fc2c0..bcc3c83b4560 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -93,9 +93,6 @@
<color name="qs_user_switcher_selected_avatar_icon_color">#202124</color>
<!-- Color of background circle of user avatars in quick settings user switcher -->
<color name="qs_user_switcher_avatar_background">#3C4043</color>
- <!-- Color of border for keyguard password input when focused -->
- <color name="bouncer_password_focus_color">@*android:color/system_secondary_dark</color>
-
<!-- Accessibility floating menu -->
<color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 462fc95b8cd1..5f6a39a91b8b 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -56,8 +56,6 @@
<color name="kg_user_switcher_restricted_avatar_icon_color">@color/GM2_grey_600</color>
<!-- Color of background circle of user avatars in keyguard user switcher -->
<color name="user_avatar_color_bg">?android:attr/colorBackgroundFloating</color>
- <!-- Color of border for keyguard password input when focused -->
- <color name="bouncer_password_focus_color">@*android:color/system_secondary_light</color>
<!-- Icon color for user avatars in user switcher quick settings -->
<color name="qs_user_switcher_avatar_icon_color">#3C4043</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 78b701caa3b6..e10925d551e2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -831,6 +831,20 @@
<!-- QuickSettings: Text to prompt the user to stop an ongoing recording [CHAR LIMIT=20] -->
<string name="qs_record_issue_stop">Stop</string>
+ <!-- QuickSettings: Issue Type Drop down options in Record Issue Start Dialog [CHAR LIMIT=50] -->
+ <string name="qs_record_issue_dropdown_header">What part of your device experience was affected?</string>
+ <!-- QuickSettings: Issue Type Drop down prompt in Record Issue Start Dialog [CHAR LIMIT=30] -->
+ <string name="qs_record_issue_dropdown_prompt">Select issue type</string>
+ <!-- QuickSettings: Screen record switch label in Record Issue Start Dialog [CHAR LIMIT=20] -->
+ <string name="qs_record_issue_dropdown_screenrecord">Screen record</string>
+
+ <!-- QuickSettings: Issue Type Drop down choices list in Record Issue Start Dialog [CHAR LIMIT=30] -->
+ <string-array name="qs_record_issue_types">
+ <item>Performance</item>
+ <item>User Interface</item>
+ <item>Battery</item>
+ </string-array>
+
<!-- QuickSettings: Label for the toggle that controls whether One-handed mode is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_onehanded_label">One-handed mode</string>
@@ -1066,9 +1080,11 @@
<!-- Description for the button that opens the widget editor on click. [CHAR LIMIT=50] -->
<string name="button_to_open_widget_editor">Open the widget editor</string>
<!-- Description for the button that removes a widget on click. [CHAR LIMIT=50] -->
- <string name="button_to_remove_widget">Remove a widget</string>
+ <string name="button_to_remove_widget">Remove</string>
<!-- Text for the button that launches the hub mode widget picker. [CHAR LIMIT=50] -->
- <string name="hub_mode_add_widget_button_text">Add Widget</string>
+ <string name="hub_mode_add_widget_button_text">Add widget</string>
+ <!-- Text for the button that exits the hub mode editing mode. [CHAR LIMIT=50] -->
+ <string name="hub_mode_editing_exit_button_text">Done</string>
<!-- Related to user switcher --><skip/>
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
index 80f70a0cd2f2..30648291366a 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
@@ -37,6 +37,10 @@ data class BiometricModalities(
val hasSfps: Boolean
get() = hasFingerprint && fingerprintProperties!!.isAnySidefpsType
+ /** If UDFPS authentication is available. */
+ val hasUdfps: Boolean
+ get() = hasFingerprint && fingerprintProperties!!.isAnyUdfpsType
+
/** If fingerprint authentication is available (and [faceProperties] is non-null). */
val hasFace: Boolean
get() = faceProperties != null
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
index fec96c675b22..317201d2c2d9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
@@ -16,8 +16,6 @@
package com.android.systemui.shared.rotation;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-
import android.annotation.DimenRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
@@ -89,8 +87,7 @@ public class FloatingRotationButton implements RotationButton {
@DimenRes int roundedContentPadding, @DimenRes int taskbarLeftMargin,
@DimenRes int taskbarBottomMargin, @DimenRes int buttonDiameter,
@DimenRes int rippleMaxWidth, @BoolRes int floatingRotationBtnPositionLeftResource) {
- mContext = context.createWindowContext(context.getDisplay(), TYPE_NAVIGATION_BAR_PANEL,
- null);
+ mContext = context;
mWindowManager = mContext.getSystemService(WindowManager.class);
mKeyButtonContainer = (ViewGroup) LayoutInflater.from(mContext).inflate(layout, null);
mKeyButtonView = mKeyButtonContainer.findViewById(keyButtonId);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index df7182b90f12..d6a5477fd096 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -16,7 +16,6 @@
package com.android.systemui.shared.system;
-import android.annotation.IntDef;
import android.os.Build;
import android.text.TextUtils;
import android.view.View;
@@ -25,59 +24,14 @@ import com.android.internal.jank.Cuj;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
public final class InteractionJankMonitorWrapper {
- // Launcher journeys.
- public static final int CUJ_APP_LAUNCH_FROM_RECENTS = Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS;
- public static final int CUJ_APP_LAUNCH_FROM_ICON = Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON;
- public static final int CUJ_APP_CLOSE_TO_HOME = Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME;
- public static final int CUJ_APP_CLOSE_TO_HOME_FALLBACK =
- Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
- public static final int CUJ_APP_CLOSE_TO_PIP = Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_PIP;
- public static final int CUJ_QUICK_SWITCH = Cuj.CUJ_LAUNCHER_QUICK_SWITCH;
- public static final int CUJ_OPEN_ALL_APPS = Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS;
- public static final int CUJ_CLOSE_ALL_APPS_SWIPE = Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE;
- public static final int CUJ_CLOSE_ALL_APPS_TO_HOME = Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME;
- public static final int CUJ_ALL_APPS_SCROLL = Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL;
- public static final int CUJ_APP_LAUNCH_FROM_WIDGET = Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET;
- public static final int CUJ_SPLIT_SCREEN_ENTER = Cuj.CUJ_SPLIT_SCREEN_ENTER;
- public static final int CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION =
- Cuj.CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION;
- public static final int CUJ_RECENTS_SCROLLING = Cuj.CUJ_RECENTS_SCROLLING;
- public static final int CUJ_APP_SWIPE_TO_RECENTS = Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS;
- public static final int CUJ_OPEN_SEARCH_RESULT = Cuj.CUJ_LAUNCHER_OPEN_SEARCH_RESULT;
- public static final int CUJ_LAUNCHER_UNFOLD_ANIM = Cuj.CUJ_LAUNCHER_UNFOLD_ANIM;
-
- @IntDef({
- CUJ_APP_LAUNCH_FROM_RECENTS,
- CUJ_APP_LAUNCH_FROM_ICON,
- CUJ_APP_CLOSE_TO_HOME,
- CUJ_APP_CLOSE_TO_HOME_FALLBACK,
- CUJ_APP_CLOSE_TO_PIP,
- CUJ_QUICK_SWITCH,
- CUJ_APP_LAUNCH_FROM_WIDGET,
- CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION,
- CUJ_RECENTS_SCROLLING,
- CUJ_APP_SWIPE_TO_RECENTS,
- CUJ_OPEN_ALL_APPS,
- CUJ_CLOSE_ALL_APPS_SWIPE,
- CUJ_CLOSE_ALL_APPS_TO_HOME,
- CUJ_OPEN_SEARCH_RESULT,
- CUJ_LAUNCHER_UNFOLD_ANIM,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CujType {
- }
-
/**
* Begin a trace session.
*
* @param v an attached view.
* @param cujType the specific {@link Cuj.CujType}.
*/
- public static void begin(View v, @CujType int cujType) {
+ public static void begin(View v, @Cuj.CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().begin(v, cujType);
}
@@ -89,7 +43,7 @@ public final class InteractionJankMonitorWrapper {
* @param cujType the specific {@link Cuj.CujType}.
* @param timeout duration to cancel the instrumentation in ms
*/
- public static void begin(View v, @CujType int cujType, long timeout) {
+ public static void begin(View v, @Cuj.CujType int cujType, long timeout) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
Configuration.Builder builder =
Configuration.Builder.withView(cujType, v)
@@ -104,7 +58,7 @@ public final class InteractionJankMonitorWrapper {
* @param cujType the specific {@link Cuj.CujType}.
* @param tag the tag to distinguish different flow of same type CUJ.
*/
- public static void begin(View v, @CujType int cujType, String tag) {
+ public static void begin(View v, @Cuj.CujType int cujType, String tag) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
Configuration.Builder builder =
Configuration.Builder.withView(cujType, v);
@@ -119,7 +73,7 @@ public final class InteractionJankMonitorWrapper {
*
* @param cujType the specific {@link Cuj.CujType}.
*/
- public static void end(@CujType int cujType) {
+ public static void end(@Cuj.CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().end(cujType);
}
@@ -127,7 +81,7 @@ public final class InteractionJankMonitorWrapper {
/**
* Cancel the trace session.
*/
- public static void cancel(@CujType int cujType) {
+ public static void cancel(@Cuj.CujType int cujType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
InteractionJankMonitor.getInstance().cancel(cujType);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index bf688698de5f..d8c1e41465db 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -103,8 +103,6 @@ public class QuickStepContract {
public static final int SYSUI_STATE_BACK_DISABLED = 1 << 22;
// The bubble stack is expanded AND the mange menu for bubbles is expanded on top of it.
public static final int SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED = 1 << 23;
- // The current app is in immersive mode
- public static final int SYSUI_STATE_IMMERSIVE_MODE = 1 << 24;
// The voice interaction session window is showing
public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25;
// Freeform windows are showing in desktop mode
@@ -162,7 +160,6 @@ public class QuickStepContract {
SYSUI_STATE_DEVICE_DOZING,
SYSUI_STATE_BACK_DISABLED,
SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
- SYSUI_STATE_IMMERSIVE_MODE,
SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
SYSUI_STATE_DEVICE_DREAMING,
@@ -247,9 +244,6 @@ public class QuickStepContract {
if ((flags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0) {
str.add("bubbles_mange_menu_expanded");
}
- if ((flags & SYSUI_STATE_IMMERSIVE_MODE) != 0) {
- str.add("immersive_mode");
- }
if ((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0) {
str.add("vis_win_showing");
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 5c206e95966b..5d63c2a92ba8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -281,7 +281,10 @@ public class KeyguardPatternView extends KeyguardInputView
setAlpha(1f);
mAppearAnimationUtils.startAnimation2d(
mLockPatternView.getCellStates(),
- () -> enableClipping(true),
+ () -> {
+ enableClipping(true);
+ mLockPatternView.invalidate();
+ },
KeyguardPatternView.this);
});
if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 9764de1993e5..36fe75f69a45 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -168,6 +168,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
+ mPasswordEntry.setDefaultFocusHighlightEnabled(false);
mOkButton = findViewById(R.id.key_enter);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 0a4378e07b45..cce2018f733f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -38,7 +38,7 @@ import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.media.AudioManager;
import android.metrics.LogMaker;
import android.os.SystemClock;
@@ -74,6 +74,7 @@ import com.android.systemui.Gefingerpoken;
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.biometrics.SideFpsUiRequestSource;
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingA11yDelegate;
@@ -486,7 +487,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mSceneContainerFlags = sceneContainerFlags;
mGlobalSettings = globalSettings;
mSessionTracker = sessionTracker;
- mSideFpsController = sideFpsController;
+ if (SideFpsControllerRefactor.isEnabled()) {
+ mSideFpsController = Optional.empty();
+ } else {
+ mSideFpsController = sideFpsController;
+ }
mFalsingA11yDelegate = falsingA11yDelegate;
mTelephonyManager = telephonyManager;
mViewMediatorCallback = viewMediatorCallback;
@@ -569,12 +574,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mView.clearFocus();
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* Shows and hides the side finger print sensor animation.
*
* @param isVisible sets whether we show or hide the side fps animation
*/
public void updateSideFpsVisibility(boolean isVisible) {
+ SideFpsControllerRefactor.assertInLegacyMode();
if (!mSideFpsController.isPresent()) {
return;
}
@@ -582,7 +589,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (isVisible) {
mSideFpsController.get().show(
SideFpsUiRequestSource.PRIMARY_BOUNCER,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD
);
} else {
mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
index ca859de73a36..24aa11e10f30 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -16,61 +16,16 @@
package com.android.systemui.accessibility
-import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.qs.tiles.ColorCorrectionTile
-import com.android.systemui.qs.tiles.ColorInversionTile
-import com.android.systemui.qs.tiles.DreamTile
-import com.android.systemui.qs.tiles.FontScalingTile
-import com.android.systemui.qs.tiles.NightDisplayTile
-import com.android.systemui.qs.tiles.OneHandedModeTile
-import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepositoryImpl
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
import dagger.Binds
import dagger.Module
-import dagger.multibindings.IntoMap
-import dagger.multibindings.StringKey
-@Module
+@Module(includes = [QSAccessibilityModule::class])
interface AccessibilityModule {
-
- /** Inject ColorInversionTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ColorInversionTile.TILE_SPEC)
- fun bindColorInversionTile(colorInversionTile: ColorInversionTile): QSTileImpl<*>
-
- /** Inject NightDisplayTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(NightDisplayTile.TILE_SPEC)
- fun bindNightDisplayTile(nightDisplayTile: NightDisplayTile): QSTileImpl<*>
-
- /** Inject ReduceBrightColorsTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ReduceBrightColorsTile.TILE_SPEC)
- fun bindReduceBrightColorsTile(reduceBrightColorsTile: ReduceBrightColorsTile): QSTileImpl<*>
-
- /** Inject OneHandedModeTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(OneHandedModeTile.TILE_SPEC)
- fun bindOneHandedModeTile(oneHandedModeTile: OneHandedModeTile): QSTileImpl<*>
-
- /** Inject ColorCorrectionTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ColorCorrectionTile.TILE_SPEC)
- fun bindColorCorrectionTile(colorCorrectionTile: ColorCorrectionTile): QSTileImpl<*>
-
- /** Inject DreamTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(DreamTile.TILE_SPEC)
- fun bindDreamTile(dreamTile: DreamTile): QSTileImpl<*>
-
- /** Inject FontScalingTile into tileMap in QSModule */
@Binds
- @IntoMap
- @StringKey(FontScalingTile.TILE_SPEC)
- fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>
+ abstract fun colorCorrectionRepository(
+ impl: ColorCorrectionRepositoryImpl
+ ): ColorCorrectionRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt
new file mode 100644
index 000000000000..6483ae44d5ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.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.accessibility.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings.Secure
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+/** Provides data related to color correction. */
+interface ColorCorrectionRepository {
+ /** Observable for whether color correction is enabled */
+ fun isEnabled(userHandle: UserHandle): Flow<Boolean>
+
+ /** Sets color correction enabled state. */
+ suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean
+}
+
+@SysUISingleton
+class ColorCorrectionRepositoryImpl
+@Inject
+constructor(
+ @Background private val bgCoroutineContext: CoroutineContext,
+ private val secureSettings: SecureSettings,
+) : ColorCorrectionRepository {
+
+ companion object {
+ const val SETTING_NAME = Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED
+ const val DISABLED = 0
+ const val ENABLED = 1
+ }
+
+ override fun isEnabled(userHandle: UserHandle): Flow<Boolean> =
+ secureSettings
+ .observerFlow(userHandle.identifier, SETTING_NAME)
+ .onStart { emit(Unit) }
+ .map { secureSettings.getIntForUser(SETTING_NAME, userHandle.identifier) == ENABLED }
+ .distinctUntilChanged()
+ .flowOn(bgCoroutineContext)
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean =
+ withContext(bgCoroutineContext) {
+ secureSettings.putIntForUser(
+ SETTING_NAME,
+ if (isEnabled) ENABLED else DISABLED,
+ userHandle.identifier
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
new file mode 100644
index 000000000000..df7fdb8e6058
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.accessibility.qs
+
+import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tiles.ColorCorrectionTile
+import com.android.systemui.qs.tiles.ColorInversionTile
+import com.android.systemui.qs.tiles.DreamTile
+import com.android.systemui.qs.tiles.FontScalingTile
+import com.android.systemui.qs.tiles.NightDisplayTile
+import com.android.systemui.qs.tiles.OneHandedModeTile
+import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.ColorCorrectionTileMapper
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionTileDataInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionUserActionInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.res.R
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoMap
+import dagger.multibindings.StringKey
+
+@Module
+interface QSAccessibilityModule {
+
+ /** Inject ColorInversionTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ColorInversionTile.TILE_SPEC)
+ fun bindColorInversionTile(colorInversionTile: ColorInversionTile): QSTileImpl<*>
+
+ /** Inject NightDisplayTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(NightDisplayTile.TILE_SPEC)
+ fun bindNightDisplayTile(nightDisplayTile: NightDisplayTile): QSTileImpl<*>
+
+ /** Inject ReduceBrightColorsTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ReduceBrightColorsTile.TILE_SPEC)
+ fun bindReduceBrightColorsTile(reduceBrightColorsTile: ReduceBrightColorsTile): QSTileImpl<*>
+
+ /** Inject OneHandedModeTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(OneHandedModeTile.TILE_SPEC)
+ fun bindOneHandedModeTile(oneHandedModeTile: OneHandedModeTile): QSTileImpl<*>
+
+ /** Inject ColorCorrectionTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ColorCorrectionTile.TILE_SPEC)
+ fun bindColorCorrectionTile(colorCorrectionTile: ColorCorrectionTile): QSTileImpl<*>
+
+ /** Inject DreamTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(DreamTile.TILE_SPEC)
+ fun bindDreamTile(dreamTile: DreamTile): QSTileImpl<*>
+
+ /** Inject FontScalingTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(FontScalingTile.TILE_SPEC)
+ fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>
+
+ companion object {
+
+ const val COLOR_CORRECTION_TILE_SPEC = "color_correction"
+
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_CORRECTION_TILE_SPEC)
+ fun provideColorCorrectionTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(COLOR_CORRECTION_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.ic_qs_color_correction,
+ labelRes = R.string.quick_settings_color_correction_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
+ /** Inject ColorCorrectionTile into tileViewModelMap in QSModule */
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_CORRECTION_TILE_SPEC)
+ fun provideColorCorrectionTileViewModel(
+ factory: QSTileViewModelFactory.Static<ColorCorrectionTileModel>,
+ mapper: ColorCorrectionTileMapper,
+ stateInteractor: ColorCorrectionTileDataInteractor,
+ userActionInteractor: ColorCorrectionUserActionInteractor
+ ): QSTileViewModel =
+ factory.create(
+ TileSpec.create(COLOR_CORRECTION_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 877afce7fe65..5fba761b2f09 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -70,6 +70,7 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor;
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
@@ -88,6 +89,8 @@ import com.android.systemui.util.concurrency.Execution;
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -101,7 +104,6 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlin.Unit;
import kotlinx.coroutines.CoroutineScope;
/**
@@ -317,7 +319,9 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null;
if (mSidefpsProps != null) {
- mSideFpsController = mSidefpsControllerFactory.get();
+ if (!SideFpsControllerRefactor.isEnabled()) {
+ mSideFpsController = mSidefpsControllerFactory.get();
+ }
}
mFingerprintManager.registerBiometricStateListener(new BiometricStateListener() {
@@ -1194,7 +1198,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
* Whether the passed userId has enrolled SFPS.
*/
public boolean isSfpsEnrolled(int userId) {
- if (mSideFpsController == null) {
+ if (mSidefpsProps == null) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 91cee9e51a93..ac99fc69b2b5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -23,9 +23,9 @@ import android.graphics.PixelFormat
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.display.DisplayManager
import android.hardware.fingerprint.FingerprintManager
@@ -58,6 +58,7 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.keyguard.KeyguardPINView
import com.android.systemui.Dumpable
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -91,7 +92,7 @@ constructor(
@Main private val mainExecutor: DelayableExecutor,
@Main private val handler: Handler,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
- @Application private val scope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
dumpManager: DumpManager,
fpsUnlockTracker: FpsUnlockTracker
) : Dumpable {
@@ -110,7 +111,7 @@ constructor(
handler,
sensorProps,
{ reason -> onOrientationChanged(reason) },
- BiometricOverlayConstants.REASON_UNKNOWN
+ BiometricRequestConstants.REASON_UNKNOWN
)
@VisibleForTesting val orientationListener = orientationReasonListener.orientationListener
@@ -169,25 +170,27 @@ constructor(
}
init {
- fpsUnlockTracker.startTracking()
- fingerprintManager?.setSidefpsController(
- object : ISidefpsController.Stub() {
- override fun show(
- sensorId: Int,
- @BiometricOverlayConstants.ShowReason reason: Int
- ) =
- if (reason.isReasonToAutoShow(activityTaskManager)) {
- show(SideFpsUiRequestSource.AUTO_SHOW, reason)
- } else {
- hide(SideFpsUiRequestSource.AUTO_SHOW)
- }
-
- override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW)
- }
- )
- listenForAlternateBouncerVisibility()
+ if (!SideFpsControllerRefactor.isEnabled) {
+ fpsUnlockTracker.startTracking()
+ fingerprintManager?.setSidefpsController(
+ object : ISidefpsController.Stub() {
+ override fun show(
+ sensorId: Int,
+ @BiometricRequestConstants.RequestReason reason: Int
+ ) =
+ if (reason.isReasonToAutoShow(activityTaskManager)) {
+ show(SideFpsUiRequestSource.AUTO_SHOW, reason)
+ } else {
+ hide(SideFpsUiRequestSource.AUTO_SHOW)
+ }
+
+ override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW)
+ }
+ )
+ listenForAlternateBouncerVisibility()
- dumpManager.registerDumpable(this)
+ dumpManager.registerDumpable(this)
+ }
}
private fun listenForAlternateBouncerVisibility() {
@@ -195,7 +198,7 @@ constructor(
alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, "SideFpsController")
}
- scope.launch {
+ applicationScope.launch {
alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
if (isVisible) {
show(SideFpsUiRequestSource.ALTERNATE_BOUNCER, REASON_AUTH_KEYGUARD)
@@ -209,8 +212,10 @@ constructor(
/** Shows the side fps overlay if not already shown. */
fun show(
request: SideFpsUiRequestSource,
- @BiometricOverlayConstants.ShowReason reason: Int = BiometricOverlayConstants.REASON_UNKNOWN
+ @BiometricRequestConstants.RequestReason
+ reason: Int = BiometricRequestConstants.REASON_UNKNOWN
) {
+ SideFpsControllerRefactor.assertInLegacyMode()
if (!displayStateInteractor.isInRearDisplayMode.value) {
requests.add(request)
mainExecutor.execute {
@@ -229,6 +234,7 @@ constructor(
/** Hides the fps overlay if shown. */
fun hide(request: SideFpsUiRequestSource) {
+ SideFpsControllerRefactor.assertInLegacyMode()
requests.remove(request)
mainExecutor.execute {
if (requests.isEmpty()) {
@@ -239,6 +245,7 @@ constructor(
/** Hide the arrow indicator. */
fun hideIndicator() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val lottieAnimationView =
overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView?
lottieAnimationView?.visibility = INVISIBLE
@@ -246,6 +253,7 @@ constructor(
/** Show the arrow indicator. */
fun showIndicator() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val lottieAnimationView =
overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView?
lottieAnimationView?.visibility = VISIBLE
@@ -279,13 +287,13 @@ constructor(
pw.println("currentRotation=${displayInfo.rotation}")
}
- private fun onOrientationChanged(@BiometricOverlayConstants.ShowReason reason: Int) {
+ private fun onOrientationChanged(@BiometricRequestConstants.RequestReason reason: Int) {
if (overlayView != null) {
createOverlayForDisplay(reason)
}
}
- private fun createOverlayForDisplay(@BiometricOverlayConstants.ShowReason reason: Int) {
+ private fun createOverlayForDisplay(@BiometricRequestConstants.RequestReason reason: Int) {
val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
overlayView = view
val display = context.display!!
@@ -395,7 +403,7 @@ private val FingerprintManager?.sideFpsSensorProperties: FingerprintSensorProper
/** Returns [True] when the device has a side fingerprint sensor. */
fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null
-@BiometricOverlayConstants.ShowReason
+@BiometricRequestConstants.RequestReason
private fun Int.isReasonToAutoShow(activityTaskManager: ActivityTaskManager): Boolean =
when (this) {
REASON_AUTH_KEYGUARD -> false
@@ -434,7 +442,7 @@ private fun Display.isNaturalOrientation(): Boolean =
private fun LottieAnimationView.addOverlayDynamicColor(
context: Context,
- @BiometricOverlayConstants.ShowReason reason: Int
+ @BiometricRequestConstants.RequestReason reason: Int
) {
fun update() {
val isKeyguard = reason == REASON_AUTH_KEYGUARD
@@ -501,7 +509,7 @@ class OrientationReasonListener(
handler: Handler,
sensorProps: FingerprintSensorPropertiesInternal,
onOrientationChanged: (reason: Int) -> Unit,
- @BiometricOverlayConstants.ShowReason var reason: Int
+ @BiometricRequestConstants.RequestReason var reason: Int
) {
val orientationListener =
BiometricDisplayListener(
@@ -516,7 +524,7 @@ class OrientationReasonListener(
/**
* The source of a request to show the side fps visual indicator. This is distinct from
- * [BiometricOverlayConstants] which corrresponds with the reason fingerprint authentication is
+ * [BiometricRequestConstants] which corresponds with the reason fingerprint authentication is
* requested.
*/
enum class SideFpsUiRequestSource {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt
index e98f6db12d34..d5e25ac84aba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt
@@ -19,6 +19,6 @@ import android.content.Context
import android.util.AttributeSet
import com.android.systemui.util.wrapper.LottieViewWrapper
-class SideFpsLottieViewWrapper
+class SideFpsIndicatorView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index bb6ef41bdfd3..65668b56a9f3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -19,10 +19,10 @@ package com.android.systemui.biometrics;
import static android.app.StatusBarManager.SESSION_BIOMETRIC_PROMPT;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR;
import static com.android.internal.util.LatencyTracker.ACTION_UDFPS_ILLUMINATE;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -106,6 +106,8 @@ import com.android.systemui.util.time.SystemClock;
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -115,8 +117,6 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlin.Unit;
-
import kotlinx.coroutines.ExperimentalCoroutinesApi;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 452cd6a7c4df..dae6d08f7331 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -21,13 +21,13 @@ import android.annotation.UiThread
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricRequestConstants.RequestReason
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.os.Build
import android.os.RemoteException
@@ -96,7 +96,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
val requestId: Long,
- @ShowReason val requestReason: Int,
+ @RequestReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
private val activityLaunchAnimator: ActivityLaunchAnimator,
@@ -461,7 +461,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
}
}
-@ShowReason
+@RequestReason
private fun Int.isImportantForAccessibility() =
this == REASON_ENROLL_FIND_SENSOR ||
this == REASON_ENROLL_ENROLLING ||
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
index e3dbcb523258..88b9e1bdfd97 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
@@ -18,13 +18,13 @@ package com.android.systemui.biometrics
import android.content.Context
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricRequestConstants.REASON_UNKNOWN
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.util.Log
import android.view.LayoutInflater
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index 72fcfe777e79..8ae6f87f4f83 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -18,8 +18,11 @@ package com.android.systemui.biometrics.dagger
import android.content.res.Resources
import com.android.internal.R
+import com.android.systemui.CoreStartable
import com.android.systemui.biometrics.EllipseOverlapDetectorParams
import com.android.systemui.biometrics.UdfpsUtils
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepositoryImpl
import com.android.systemui.biometrics.data.repository.DisplayStateRepository
import com.android.systemui.biometrics.data.repository.DisplayStateRepositoryImpl
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
@@ -33,11 +36,14 @@ import com.android.systemui.biometrics.data.repository.PromptRepositoryImpl
import com.android.systemui.biometrics.udfps.BoundingBoxOverlapDetector
import com.android.systemui.biometrics.udfps.EllipseOverlapDetector
import com.android.systemui.biometrics.udfps.OverlapDetector
+import com.android.systemui.biometrics.ui.binder.SideFpsOverlayViewBinder
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.concurrency.ThreadFactory
import dagger.Binds
import dagger.Module
import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
import java.util.concurrent.Executor
import javax.inject.Qualifier
@@ -46,6 +52,11 @@ import javax.inject.Qualifier
interface BiometricsModule {
@Binds
+ @IntoMap
+ @ClassKey(SideFpsOverlayViewBinder::class)
+ fun bindsSideFpsOverlayViewBinder(viewBinder: SideFpsOverlayViewBinder): CoreStartable
+
+ @Binds
@SysUISingleton
fun faceSettings(impl: FaceSettingsRepositoryImpl): FaceSettingsRepository
@@ -57,6 +68,10 @@ interface BiometricsModule {
@Binds
@SysUISingleton
+ fun biometricStatusRepository(impl: BiometricStatusRepositoryImpl): BiometricStatusRepository
+
+ @Binds
+ @SysUISingleton
fun fingerprintRepository(
impl: FingerprintPropertyRepositoryImpl
): FingerprintPropertyRepository
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
new file mode 100644
index 000000000000..ad2136af4b86
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.biometrics.data.repository
+
+import android.hardware.biometrics.AuthenticationStateListener
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.shareIn
+
+/** A repository for the state of biometric authentication. */
+interface BiometricStatusRepository {
+ /**
+ * The logical reason for the current fingerprint auth operation if one is on-going, otherwise
+ * [NotRunning].
+ */
+ val fingerprintAuthenticationReason: Flow<AuthenticationReason>
+}
+
+@SysUISingleton
+class BiometricStatusRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val biometricManager: BiometricManager?
+) : BiometricStatusRepository {
+
+ override val fingerprintAuthenticationReason: Flow<AuthenticationReason> =
+ conflatedCallbackFlow {
+ val updateFingerprintAuthenticateReason = { reason: AuthenticationReason ->
+ trySendWithFailureLogging(
+ reason,
+ TAG,
+ "Error sending fingerprintAuthenticateReason reason"
+ )
+ }
+
+ val authenticationStateListener =
+ object : AuthenticationStateListener.Stub() {
+ override fun onAuthenticationStarted(requestReason: Int) {
+ val authenticationReason =
+ when (requestReason) {
+ REASON_AUTH_BP ->
+ AuthenticationReason.BiometricPromptAuthentication
+ REASON_AUTH_KEYGUARD ->
+ AuthenticationReason.DeviceEntryAuthentication
+ REASON_AUTH_OTHER -> AuthenticationReason.OtherAuthentication
+ REASON_AUTH_SETTINGS ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.OTHER
+ )
+ REASON_ENROLL_ENROLLING ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_ENROLLING
+ )
+ REASON_ENROLL_FIND_SENSOR ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ else -> AuthenticationReason.Unknown
+ }
+ updateFingerprintAuthenticateReason(authenticationReason)
+ }
+
+ override fun onAuthenticationStopped() {
+ updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
+ }
+ }
+
+ updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
+ biometricManager?.registerAuthenticationStateListener(authenticationStateListener)
+ awaitClose {
+ biometricManager?.unregisterAuthenticationStateListener(
+ authenticationStateListener
+ )
+ }
+ }
+ .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
+
+ companion object {
+ private const val TAG = "BiometricStatusRepositoryImpl"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
index b9b2fd8875d9..ec3fd9f7da35 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
@@ -15,6 +15,8 @@
*/
package com.android.systemui.biometrics.domain
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
import com.android.systemui.biometrics.domain.interactor.CredentialInteractor
import com.android.systemui.biometrics.domain.interactor.CredentialInteractorImpl
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
@@ -38,6 +40,12 @@ interface BiometricsDomainLayerModule {
@Binds
@SysUISingleton
+ fun providesBiometricStatusInteractor(
+ impl: BiometricStatusInteractorImpl
+ ): BiometricStatusInteractor
+
+ @Binds
+ @SysUISingleton
fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
new file mode 100644
index 000000000000..55a2d3d7563e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.biometrics.domain.interactor
+
+import android.app.ActivityTaskManager
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** Encapsulates business logic for interacting with biometric authentication state. */
+interface BiometricStatusInteractor {
+ /**
+ * The logical reason for the current side fingerprint sensor auth operation if one is on-going,
+ * filtered for when the overlay should be shown, otherwise [NotRunning].
+ */
+ val sfpsAuthenticationReason: Flow<AuthenticationReason>
+}
+
+class BiometricStatusInteractorImpl
+@Inject
+constructor(
+ private val activityTaskManager: ActivityTaskManager,
+ biometricStatusRepository: BiometricStatusRepository,
+) : BiometricStatusInteractor {
+
+ override val sfpsAuthenticationReason: Flow<AuthenticationReason> =
+ biometricStatusRepository.fingerprintAuthenticationReason.map { reason: AuthenticationReason
+ ->
+ if (reason.isReasonToAlwaysUpdateSfpsOverlay(activityTaskManager)) {
+ reason
+ } else {
+ AuthenticationReason.NotRunning
+ }
+ }
+
+ companion object {
+ private const val TAG = "BiometricStatusInteractor"
+ }
+}
+
+/** True if the sfps overlay should always be updated for this request source, false otherwise. */
+private fun AuthenticationReason.isReasonToAlwaysUpdateSfpsOverlay(
+ activityTaskManager: ActivityTaskManager
+): Boolean =
+ when (this) {
+ AuthenticationReason.DeviceEntryAuthentication -> false
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER) ->
+ when (activityTaskManager.topClass()) {
+ // TODO(b/186176653): exclude fingerprint overlays from this list view
+ "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false
+ else -> true
+ }
+ else -> true
+ }
+
+internal fun ActivityTaskManager.topClass(): String =
+ getTasks(1).firstOrNull()?.topActivity?.className ?: ""
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
index f51379940640..f4231ac01fee 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
@@ -141,7 +141,6 @@ constructor(
}
}
}
-
SideFpsSensorLocation(
left = sensorLeft,
top = sensorTop,
@@ -149,7 +148,15 @@ constructor(
isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation
)
}
- .distinctUntilChanged()
+ .distinctUntilChanged(
+ areEquivalent = { old: SideFpsSensorLocation, new: SideFpsSensorLocation ->
+ old.left == new.left &&
+ old.top == new.top &&
+ old.length == new.length &&
+ old.isSensorVerticalInDefaultOrientation ==
+ new.isSensorVerticalInDefaultOrientation
+ }
+ )
.onEach {
logger.sensorLocationStateChanged(
it.left,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt
new file mode 100644
index 000000000000..899b07e89964
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.biometrics.shared
+
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+import com.android.systemui.shared.Flags
+
+/** Helper for reading or using the sidefps controller refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object SideFpsControllerRefactor {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.sidefpsControllerRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt
new file mode 100644
index 000000000000..0c3debbe0fc4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.biometrics.shared.model
+
+/**
+ * The logical reason for a fingerprint auth operation if one is on-going, otherwise [NotRunning].
+ */
+sealed interface AuthenticationReason {
+ /** Device entry requested authentication */
+ data object DeviceEntryAuthentication : AuthenticationReason
+
+ /** Settings requested authentication */
+ data class SettingsAuthentication(val settingsOperation: SettingsOperations) :
+ AuthenticationReason
+
+ /** App requested authentication */
+ data object BiometricPromptAuthentication : AuthenticationReason
+
+ /** Authentication requested for other reason */
+ data object OtherAuthentication : AuthenticationReason
+
+ /** Authentication requested for unknown reason */
+ data object Unknown : AuthenticationReason
+
+ /** Authentication is not running */
+ data object NotRunning : AuthenticationReason
+
+ /** Settings operations that request biometric authentication */
+ enum class SettingsOperations {
+ ENROLL_ENROLLING,
+ ENROLL_FIND_SENSOR,
+ OTHER
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt
new file mode 100644
index 000000000000..0b3005530e6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.biometrics.shared.model
+
+import com.airbnb.lottie.model.KeyPath
+
+/** Represents properties of a LottieAnimationView callback */
+data class LottieCallback(val keypath: KeyPath, val color: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 32d9067bd9e4..90e4a3821634 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -376,6 +376,22 @@ object BiometricViewBinder {
}
}
+ // Talkback directional guidance
+ backgroundView.setOnHoverListener { _, event ->
+ launch {
+ viewModel.onAnnounceAccessibilityHint(
+ event,
+ accessibilityManager.isTouchExplorationEnabled
+ )
+ }
+ false
+ }
+ launch {
+ viewModel.accessibilityHint.collect { message ->
+ if (message.isNotBlank()) view.announceForAccessibility(message)
+ }
+ }
+
// Play haptics
launch {
viewModel.hapticsToPlay.collect { hapticFeedbackConstant ->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
new file mode 100644
index 000000000000..a8c9446fd689
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -0,0 +1,224 @@
+/*
+ * 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.biometrics.ui.binder
+
+import android.content.Context
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.view.LayoutInflater
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityEvent
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.LottieComposition
+import com.airbnb.lottie.LottieProperty
+import com.android.app.animation.Interpolators
+import com.android.keyguard.KeyguardPINView
+import com.android.systemui.CoreStartable
+import com.android.systemui.biometrics.FpsUnlockTracker
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.NotRunning
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.launch
+
+/** Binds the side fingerprint sensor indicator view to [SideFpsOverlayViewModel]. */
+@SysUISingleton
+class SideFpsOverlayViewBinder
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Application private val applicationContext: Context,
+ private val biometricStatusInteractor: BiometricStatusInteractor,
+ private val displayStateInteractor: DisplayStateInteractor,
+ private val deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor,
+ private val fpsUnlockTracker: FpsUnlockTracker,
+ private val layoutInflater: LayoutInflater,
+ private val sideFpsProgressBarViewModel: SideFpsProgressBarViewModel,
+ private val sfpsSensorInteractor: SideFpsSensorInteractor,
+ private val windowManager: WindowManager
+) : CoreStartable {
+
+ override fun start() {
+ if (!SideFpsControllerRefactor.isEnabled) {
+ return
+ }
+ applicationScope
+ .launch {
+ combine(
+ biometricStatusInteractor.sfpsAuthenticationReason,
+ deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry,
+ sideFpsProgressBarViewModel.isVisible,
+ ::Triple
+ )
+ .sample(displayStateInteractor.isInRearDisplayMode, ::Pair)
+ .collect { (combinedFlows, isInRearDisplayMode: Boolean) ->
+ val (
+ systemServerAuthReason,
+ showIndicatorForDeviceEntry,
+ progressBarIsVisible) =
+ combinedFlows
+ if (!isInRearDisplayMode) {
+ if (progressBarIsVisible) {
+ hide()
+ } else if (systemServerAuthReason != NotRunning) {
+ show()
+ } else if (showIndicatorForDeviceEntry) {
+ show()
+ } else {
+ hide()
+ }
+ }
+ }
+ }
+ .invokeOnCompletion { fpsUnlockTracker.stopTracking() }
+ }
+
+ private var overlayView: View? = null
+ private var lottie: LottieAnimationView? = null
+
+ /** Show the side fingerprint sensor indicator */
+ private fun show() {
+ overlayView?.let {
+ if (it.isAttachedToWindow) {
+ lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
+ lottie?.pauseAnimation()
+ windowManager.removeView(it)
+ }
+ }
+
+ overlayView = layoutInflater.inflate(R.layout.sidefps_view, null, false)
+ val overlayViewModel =
+ SideFpsOverlayViewModel(
+ applicationContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel
+ )
+ bind(overlayView!!, overlayViewModel, fpsUnlockTracker, windowManager)
+ overlayView!!.visibility = View.INVISIBLE
+ windowManager.addView(overlayView, overlayViewModel.defaultOverlayViewParams)
+ }
+
+ /** Hide the side fingerprint sensor indicator */
+ private fun hide() {
+ if (overlayView != null) {
+ windowManager.removeView(overlayView)
+ overlayView = null
+ }
+ }
+
+ companion object {
+ private const val TAG = "SideFpsOverlayViewBinder"
+
+ /** Binds overlayView (side fingerprint sensor indicator view) to SideFpsOverlayViewModel */
+ fun bind(
+ overlayView: View,
+ viewModel: SideFpsOverlayViewModel,
+ fpsUnlockTracker: FpsUnlockTracker,
+ windowManager: WindowManager
+ ) {
+ overlayView.repeatWhenAttached {
+ fpsUnlockTracker.startTracking()
+
+ val lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
+ lottie.addLottieOnCompositionLoadedListener { composition: LottieComposition ->
+ viewModel.setLottieBounds(composition.bounds)
+ overlayView.visibility = View.VISIBLE
+ }
+ it.alpha = 0f
+ val overlayShowAnimator =
+ it.animate()
+ .alpha(1f)
+ .setDuration(KeyguardPINView.ANIMATION_DURATION)
+ .setInterpolator(Interpolators.ALPHA_IN)
+
+ overlayShowAnimator.start()
+
+ it.setAccessibilityDelegate(
+ object : View.AccessibilityDelegate() {
+ override fun dispatchPopulateAccessibilityEvent(
+ host: View,
+ event: AccessibilityEvent
+ ): Boolean {
+ return if (
+ event.getEventType() ===
+ android.view.accessibility.AccessibilityEvent
+ .TYPE_WINDOW_STATE_CHANGED
+ ) {
+ true
+ } else {
+ super.dispatchPopulateAccessibilityEvent(host, event)
+ }
+ }
+ }
+ )
+
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.lottieCallbacks.collect { callbacks ->
+ lottie.addOverlayDynamicColor(callbacks)
+ }
+ }
+
+ launch {
+ viewModel.overlayViewParams.collect { params ->
+ windowManager.updateViewLayout(it, params)
+ lottie.resumeAnimation()
+ }
+ }
+
+ launch {
+ viewModel.overlayViewProperties.collect { properties ->
+ it.rotation = properties.overlayViewRotation
+ lottie.setAnimation(properties.indicatorAsset)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+private fun LottieAnimationView.addOverlayDynamicColor(colorCallbacks: List<LottieCallback>) {
+ addLottieOnCompositionLoadedListener {
+ for (callback in colorCallbacks) {
+ addValueCallback(callback.keypath, LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(callback.color, PorterDuff.Mode.SRC_ATOP)
+ }
+ }
+ resumeAnimation()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 647aaf392ed8..6d0a58e202bd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -21,9 +21,12 @@ import android.hardware.biometrics.BiometricPrompt
import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
+import com.android.systemui.Flags.bpTalkback
+import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.DisplayRotation
@@ -35,7 +38,9 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -49,7 +54,9 @@ class PromptViewModel
constructor(
displayStateInteractor: DisplayStateInteractor,
promptSelectorInteractor: PromptSelectorInteractor,
- @Application context: Context,
+ @Application private val context: Context,
+ private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
+ private val udfpsUtils: UdfpsUtils
) {
/** The set of modalities available for this prompt */
val modalities: Flow<BiometricModalities> =
@@ -69,6 +76,11 @@ constructor(
val faceIconHeight: Int =
context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size)
+ private val _accessibilityHint = MutableSharedFlow<String>()
+
+ /** Hint for talkback directional guidance */
+ val accessibilityHint: Flow<String> = _accessibilityHint.asSharedFlow()
+
private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false)
/** If the user is currently authenticating (i.e. at least one biometric is scanning). */
@@ -516,6 +528,40 @@ constructor(
return false
}
+ /** Sets the message used for UDFPS directional guidance */
+ suspend fun onAnnounceAccessibilityHint(
+ event: MotionEvent,
+ touchExplorationEnabled: Boolean,
+ ): Boolean {
+ if (bpTalkback() && modalities.first().hasUdfps && touchExplorationEnabled) {
+ // TODO(b/315184924): Remove uses of UdfpsUtils
+ val scaledTouch =
+ udfpsUtils.getTouchInNativeCoordinates(
+ event.getPointerId(0),
+ event,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ if (
+ !udfpsUtils.isWithinSensorArea(
+ event.getPointerId(0),
+ event,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ ) {
+ _accessibilityHint.emit(
+ udfpsUtils.onTouchOutsideOfSensorArea(
+ touchExplorationEnabled,
+ context,
+ scaledTouch.x,
+ scaledTouch.y,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ )
+ }
+ }
+ return false
+ }
+
/**
* Switch to the credential view.
*
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
new file mode 100644
index 000000000000..ce726034913f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
@@ -0,0 +1,229 @@
+/*
+ * 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.biometrics.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Color
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.graphics.Rect
+import android.view.Gravity
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
+import com.airbnb.lottie.model.KeyPath
+import com.android.systemui.biometrics.Utils
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.domain.model.SideFpsSensorLocation
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+
+/** Models UI of the side fingerprint sensor indicator view. */
+class SideFpsOverlayViewModel
+@Inject
+constructor(
+ @Application private val applicationContext: Context,
+ biometricStatusInteractor: BiometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor: DisplayStateInteractor,
+ sfpsSensorInteractor: SideFpsSensorInteractor,
+ sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+) {
+ /** Contains properties of the side fingerprint sensor indicator */
+ data class OverlayViewProperties(
+ /** The raw asset for the indicator animation */
+ val indicatorAsset: Int,
+ /** Rotation of the overlayView */
+ val overlayViewRotation: Float,
+ )
+
+ private val _lottieBounds: MutableStateFlow<Rect?> = MutableStateFlow(null)
+
+ /** Used for setting lottie bounds once the composition has loaded. */
+ fun setLottieBounds(bounds: Rect) {
+ _lottieBounds.value = bounds
+ }
+
+ private val displayRotation = displayStateInteractor.currentRotation
+ private val sensorLocation = sfpsSensorInteractor.sensorLocation
+
+ /** Default LayoutParams for the overlayView */
+ val defaultOverlayViewParams: WindowManager.LayoutParams
+ get() =
+ WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
+ PixelFormat.TRANSLUCENT
+ )
+ .apply {
+ title = TAG
+ fitInsetsTypes = 0 // overrides default, avoiding status bars during layout
+ gravity = Gravity.TOP or Gravity.LEFT
+ layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION
+ }
+
+ private val indicatorAsset: Flow<Int> =
+ combine(displayRotation, sensorLocation) { rotation: DisplayRotation, sensorLocation ->
+ val yAligned = sensorLocation.isSensorVerticalInDefaultOrientation
+ val newAsset: Int =
+ when (rotation) {
+ DisplayRotation.ROTATION_0 ->
+ if (yAligned) {
+ R.raw.sfps_pulse
+ } else {
+ R.raw.sfps_pulse_landscape
+ }
+ DisplayRotation.ROTATION_180 ->
+ if (yAligned) {
+ R.raw.sfps_pulse
+ } else {
+ R.raw.sfps_pulse_landscape
+ }
+ else ->
+ if (yAligned) {
+ R.raw.sfps_pulse_landscape
+ } else {
+ R.raw.sfps_pulse
+ }
+ }
+ newAsset
+ }
+ .distinctUntilChanged()
+
+ private val overlayViewRotation: Flow<Float> =
+ combine(
+ displayRotation,
+ sensorLocation,
+ ) { rotation: DisplayRotation, sensorLocation ->
+ val yAligned = sensorLocation.isSensorVerticalInDefaultOrientation
+ when (rotation) {
+ DisplayRotation.ROTATION_90 -> if (yAligned) 0f else 180f
+ DisplayRotation.ROTATION_180 -> 180f
+ DisplayRotation.ROTATION_270 -> if (yAligned) 180f else 0f
+ else -> 0f
+ }
+ }
+ .distinctUntilChanged()
+
+ /** Contains properties (animation asset and view rotation) for overlayView */
+ val overlayViewProperties: Flow<OverlayViewProperties> =
+ combine(indicatorAsset, overlayViewRotation) { asset: Int, rotation: Float ->
+ OverlayViewProperties(asset, rotation)
+ }
+
+ /** LayoutParams for placement of overlayView (the side fingerprint sensor indicator view) */
+ val overlayViewParams: Flow<WindowManager.LayoutParams> =
+ combine(
+ _lottieBounds,
+ sensorLocation,
+ displayRotation,
+ ) { bounds: Rect?, sensorLocation: SideFpsSensorLocation, displayRotation: DisplayRotation
+ ->
+ val topLeft = Point(sensorLocation.left, sensorLocation.top)
+
+ if (sensorLocation.isSensorVerticalInDefaultOrientation) {
+ if (displayRotation == DisplayRotation.ROTATION_0) {
+ topLeft.x -= bounds!!.width()
+ } else if (displayRotation == DisplayRotation.ROTATION_270) {
+ topLeft.y -= bounds!!.height()
+ }
+ } else {
+ if (displayRotation == DisplayRotation.ROTATION_180) {
+ topLeft.y -= bounds!!.height()
+ } else if (displayRotation == DisplayRotation.ROTATION_270) {
+ topLeft.x -= bounds!!.width()
+ }
+ }
+ defaultOverlayViewParams.apply {
+ x = topLeft.x
+ y = topLeft.y
+ }
+ }
+
+ /** List of LottieCallbacks use for adding dynamic color to the overlayView */
+ val lottieCallbacks: Flow<List<LottieCallback>> =
+ combine(
+ biometricStatusInteractor.sfpsAuthenticationReason,
+ deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry.distinctUntilChanged(),
+ sideFpsProgressBarViewModel.isVisible,
+ ) { reason: AuthenticationReason, showIndicatorForDeviceEntry: Boolean, progressBarIsVisible
+ ->
+ val callbacks = mutableListOf<LottieCallback>()
+ if (showIndicatorForDeviceEntry) {
+ val indicatorColor =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorPrimaryFixed
+ )
+ val outerRimColor =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorPrimaryFixedDim
+ )
+ val chevronFill =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
+ )
+ callbacks.add(LottieCallback(KeyPath(".blue600", "**"), indicatorColor))
+ callbacks.add(LottieCallback(KeyPath(".blue400", "**"), outerRimColor))
+ callbacks.add(LottieCallback(KeyPath(".black", "**"), chevronFill))
+ } else {
+ if (!isDarkMode(applicationContext)) {
+ callbacks.add(LottieCallback(KeyPath(".black", "**"), Color.WHITE))
+ }
+ for (key in listOf(".blue600", ".blue400")) {
+ callbacks.add(
+ LottieCallback(
+ KeyPath(key, "**"),
+ applicationContext.getColor(
+ com.android.settingslib.color.R.color.settingslib_color_blue400
+ ),
+ )
+ )
+ }
+ }
+ callbacks
+ }
+
+ companion object {
+ private const val TAG = "SideFpsOverlayViewModel"
+ }
+}
+
+private fun isDarkMode(context: Context): Boolean {
+ val darkMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ return darkMode == Configuration.UI_MODE_NIGHT_YES
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
index 1e0e16c5472f..c2a1d8fe26c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
@@ -18,6 +18,7 @@ package com.android.systemui.bouncer.data.repository
import android.os.Build
import android.util.Log
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.dagger.SysUISingleton
@@ -121,6 +122,7 @@ interface KeyguardBouncerRepository {
fun setAlternateBouncerUIAvailable(isAvailable: Boolean)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
fun setSideFpsShowing(isShowing: Boolean)
}
@@ -261,7 +263,9 @@ constructor(
_isBackButtonEnabled.value = isBackButtonEnabled
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
override fun setSideFpsShowing(isShowing: Boolean) {
+ SideFpsControllerRefactor.assertInLegacyMode()
_sideFpsShowing.value = isShowing
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index aa7758f9380f..621ca5dc6f5a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -28,6 +28,7 @@ import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.DejankUtils
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
@@ -116,9 +117,11 @@ constructor(
/** Allow for interaction when just about fully visible */
val isInteractable: Flow<Boolean> = bouncerExpansion.map { it > 0.9 }
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
val sideFpsShowing: Flow<Boolean> = repository.sideFpsShowing
private var currentUserActiveUnlockRunning = false
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** This callback needs to be a class field so it does not get garbage collected. */
val keyguardUpdateMonitorCallback =
object : KeyguardUpdateMonitorCallback() {
@@ -135,7 +138,10 @@ constructor(
}
init {
- keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ }
applicationScope.launch {
trustRepository.isCurrentUserActiveUnlockRunning.collect {
currentUserActiveUnlockRunning = it
@@ -333,8 +339,10 @@ constructor(
repository.setPrimaryStartDisappearAnimation(runnable)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Determine whether to show the side fps animation. */
fun updateSideFpsVisibility() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val sfpsEnabled: Boolean =
context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
val fpsDetectionRunning: Boolean = keyguardUpdateMonitor.isFingerprintDetectionRunning
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index ac3d4b6c853b..5dcd6615509d 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -27,6 +27,7 @@ import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.bouncer.ui.BouncerViewDelegate
@@ -233,15 +234,21 @@ object KeyguardBouncerViewBinder {
.collect { view.systemUiVisibility = it }
}
- launch {
- viewModel.shouldUpdateSideFps.collect {
- viewModel.updateSideFpsVisibility()
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ launch {
+ viewModel.shouldUpdateSideFps.collect {
+ viewModel.updateSideFpsVisibility()
+ }
}
}
- launch {
- viewModel.sideFpsShowing.collect {
- securityContainerController.updateSideFpsVisibility(it)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ launch {
+ viewModel.sideFpsShowing.collect {
+ securityContainerController.updateSideFpsVisibility(it)
+ }
}
}
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
index 649ae2fb1007..1c9d1f01e89e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.ui.viewmodel
import android.view.View
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.bouncer.ui.BouncerView
@@ -61,9 +62,11 @@ constructor(
/** Observe whether keyguard is authenticated already. */
val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticatedBiometrics
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Observe whether the side fps is showing. */
val sideFpsShowing: Flow<Boolean> = interactor.sideFpsShowing
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Observe whether we should update fps is showing. */
val shouldUpdateSideFps: Flow<Unit> =
merge(
@@ -87,7 +90,9 @@ constructor(
interactor.onMessageShown()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
fun updateSideFpsVisibility() {
+ SideFpsControllerRefactor.assertInLegacyMode()
interactor.updateSideFpsVisibility()
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
index 3119b9e98bac..1f4be4060223 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
@@ -18,18 +18,26 @@ package com.android.systemui.communal.data.repository
import com.android.systemui.Flags.communalHub
import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.scene.shared.model.SceneKey
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
/** Encapsulates the state of communal mode. */
interface CommunalRepository {
@@ -45,14 +53,26 @@ interface CommunalRepository {
*/
val desiredScene: StateFlow<CommunalSceneKey>
+ /** Exposes the transition state of the communal [SceneTransitionLayout]. */
+ val transitionState: StateFlow<ObservableCommunalTransitionState>
+
/** Updates the requested scene. */
fun setDesiredScene(desiredScene: CommunalSceneKey)
+
+ /**
+ * Updates the transition state of the hub [SceneTransitionLayout].
+ *
+ * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ */
+ fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?)
}
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class CommunalRepositoryImpl
@Inject
constructor(
+ @Background backgroundScope: CoroutineScope,
private val featureFlagsClassic: FeatureFlagsClassic,
sceneContainerFlags: SceneContainerFlags,
sceneContainerRepository: SceneContainerRepository,
@@ -61,13 +81,34 @@ constructor(
get() = featureFlagsClassic.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) && communalHub()
private val _desiredScene: MutableStateFlow<CommunalSceneKey> =
- MutableStateFlow(CommunalSceneKey.Blank)
+ MutableStateFlow(CommunalSceneKey.DEFAULT)
override val desiredScene: StateFlow<CommunalSceneKey> = _desiredScene.asStateFlow()
+ private val defaultTransitionState =
+ ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT)
+ private val _transitionState = MutableStateFlow<Flow<ObservableCommunalTransitionState>?>(null)
+ override val transitionState: StateFlow<ObservableCommunalTransitionState> =
+ _transitionState
+ .flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
+ .stateIn(
+ scope = backgroundScope,
+ started = SharingStarted.Lazily,
+ initialValue = defaultTransitionState,
+ )
+
override fun setDesiredScene(desiredScene: CommunalSceneKey) {
_desiredScene.value = desiredScene
}
+ /**
+ * Updates the transition state of the hub [SceneTransitionLayout].
+ *
+ * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ */
+ override fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+ _transitionState.value = transitionState
+ }
+
override val isCommunalHubShowing: Flow<Boolean> =
if (sceneContainerFlags.isEnabled()) {
sceneContainerRepository.desiredScene.map { scene -> scene.key == SceneKey.Communal }
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 e630fd4e3c54..e342c6bca6fa 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
@@ -25,6 +25,7 @@ import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -62,6 +63,19 @@ constructor(
*/
val desiredScene: StateFlow<CommunalSceneKey> = communalRepository.desiredScene
+ /** Transition state of the hub mode. */
+ val transitionState: StateFlow<ObservableCommunalTransitionState> =
+ communalRepository.transitionState
+
+ /**
+ * Updates the transition state of the hub [SceneTransitionLayout].
+ *
+ * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ */
+ fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+ communalRepository.setTransitionState(transitionState)
+ }
+
/**
* Flow that emits a boolean if the communal UI is showing, ie. the [desiredScene] is the
* [CommunalSceneKey.Communal].
@@ -108,7 +122,7 @@ constructor(
if (!smartspaceRepository.isSmartspaceRemoteViewsEnabled) {
flowOf(emptyList())
} else {
- smartspaceRepository.lockscreenSmartspaceTargets.map { targets ->
+ smartspaceRepository.communalSmartspaceTargets.map { targets ->
targets
.filter { target ->
target.featureType == SmartspaceTarget.FEATURE_TIMER &&
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt
index 2be909c8e6d0..c68dd4ff271c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt
@@ -29,4 +29,8 @@ sealed class CommunalSceneKey(
override fun toString(): String {
return loggingName
}
+
+ companion object {
+ val DEFAULT = Blank
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/ObservableCommunalTransitionState.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/ObservableCommunalTransitionState.kt
new file mode 100644
index 000000000000..d834715768c9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/ObservableCommunalTransitionState.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.shared.model
+
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * This is a fork of the `com.android.compose.animation.scene.ObservableTransitionState` class.
+ *
+ * TODO(b/315490861): remove this fork, once we can compile Compose into System UI.
+ */
+sealed class ObservableCommunalTransitionState {
+ /** No transition/animation is currently running. */
+ data class Idle(val scene: CommunalSceneKey) : ObservableCommunalTransitionState()
+
+ /** There is a transition animating between two scenes. */
+ data class Transition(
+ val fromScene: CommunalSceneKey,
+ val toScene: CommunalSceneKey,
+ val progress: Flow<Float>,
+
+ /**
+ * Whether the transition was originally triggered by user input rather than being
+ * programmatic. If this value is initially true, it will remain true until the transition
+ * fully completes, even if the user input that triggered the transition has ended. Any
+ * sub-transitions launched by this one will inherit this value. For example, if the user
+ * drags a pointer but does not exceed the threshold required to transition to another
+ * scene, this value will remain true after the pointer is no longer touching the screen and
+ * will be true in any transition created to animate back to the original position.
+ */
+ val isInitiatedByUserInput: Boolean,
+
+ /**
+ * Whether user input is currently driving the transition. For example, if a user is
+ * dragging a pointer, this emits true. Once they lift their finger, this emits false while
+ * the transition completes/settles.
+ */
+ val isUserInputOngoing: Flow<Boolean>,
+ ) : ObservableCommunalTransitionState()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
new file mode 100644
index 000000000000..c5610c877f57
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
@@ -0,0 +1,195 @@
+/*
+ * 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.smartspace
+
+import android.app.smartspace.SmartspaceConfig
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.app.smartspace.SmartspaceTarget
+import android.content.Context
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_GLANCEABLE_HUB
+import com.android.systemui.smartspace.SmartspacePrecondition
+import com.android.systemui.smartspace.SmartspaceTargetFilter
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_PRECONDITION
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_TARGET_FILTER
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN
+import com.android.systemui.util.concurrency.Execution
+import java.util.Optional
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Named
+
+/** Controller for managing the smartspace view on the dream */
+@SysUISingleton
+class CommunalSmartspaceController
+@Inject
+constructor(
+ private val context: Context,
+ private val smartspaceManager: SmartspaceManager?,
+ private val execution: Execution,
+ @Main private val uiExecutor: Executor,
+ @Named(DREAM_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
+ @Named(DREAM_SMARTSPACE_TARGET_FILTER)
+ private val optionalTargetFilter: Optional<SmartspaceTargetFilter>,
+ @Named(GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>,
+) {
+ companion object {
+ private const val TAG = "CommunalSmartspaceCtrlr"
+ }
+
+ private var session: SmartspaceSession? = null
+ private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
+ private var targetFilter: SmartspaceTargetFilter? = optionalTargetFilter.orElse(null)
+
+ // A shadow copy of listeners is maintained to track whether the session should remain open.
+ private var listeners = mutableSetOf<SmartspaceTargetListener>()
+
+ private var unfilteredListeners = mutableSetOf<SmartspaceTargetListener>()
+
+ // Smartspace can be used on multiple displays, such as when the user casts their screen
+ private var smartspaceViews = mutableSetOf<SmartspaceView>()
+
+ var preconditionListener =
+ object : SmartspacePrecondition.Listener {
+ override fun onCriteriaChanged() {
+ reloadSmartspace()
+ }
+ }
+
+ init {
+ precondition.addListener(preconditionListener)
+ }
+
+ var filterListener =
+ object : SmartspaceTargetFilter.Listener {
+ override fun onCriteriaChanged() {
+ reloadSmartspace()
+ }
+ }
+
+ init {
+ targetFilter?.addListener(filterListener)
+ }
+
+ private val sessionListener =
+ SmartspaceSession.OnTargetsAvailableListener { targets ->
+ execution.assertIsMainThread()
+
+ val filteredTargets =
+ targets.filter { targetFilter?.filterSmartspaceTarget(it) ?: true }
+ plugin?.onTargetsAvailable(filteredTargets)
+ }
+
+ private fun hasActiveSessionListeners(): Boolean {
+ return smartspaceViews.isNotEmpty() ||
+ listeners.isNotEmpty() ||
+ unfilteredListeners.isNotEmpty()
+ }
+
+ private fun connectSession() {
+ if (smartspaceManager == null) {
+ return
+ }
+ if (plugin == null) {
+ return
+ }
+ if (session != null || !hasActiveSessionListeners()) {
+ return
+ }
+
+ if (!precondition.conditionsMet()) {
+ return
+ }
+
+ val newSession =
+ smartspaceManager.createSmartspaceSession(
+ SmartspaceConfig.Builder(context, UI_SURFACE_GLANCEABLE_HUB).build()
+ )
+ Log.d(TAG, "Starting smartspace session for dream")
+ newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
+ this.session = newSession
+
+ plugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
+
+ reloadSmartspace()
+ }
+
+ /** Disconnects the smartspace view from the smartspace service and cleans up any resources. */
+ private fun disconnect() {
+ if (hasActiveSessionListeners()) return
+
+ execution.assertIsMainThread()
+
+ if (session == null) {
+ return
+ }
+
+ session?.let {
+ it.removeOnTargetsAvailableListener(sessionListener)
+ it.close()
+ }
+
+ session = null
+
+ plugin?.registerSmartspaceEventNotifier(null)
+ plugin?.onTargetsAvailable(emptyList())
+ Log.d(TAG, "Ending smartspace session for dream")
+ }
+
+ fun addListener(listener: SmartspaceTargetListener) {
+ addAndRegisterListener(listener, plugin)
+ }
+
+ fun removeListener(listener: SmartspaceTargetListener) {
+ removeAndUnregisterListener(listener, plugin)
+ }
+
+ private fun addAndRegisterListener(
+ listener: SmartspaceTargetListener,
+ smartspaceDataPlugin: BcSmartspaceDataPlugin?
+ ) {
+ execution.assertIsMainThread()
+ smartspaceDataPlugin?.registerListener(listener)
+ listeners.add(listener)
+
+ connectSession()
+ }
+
+ private fun removeAndUnregisterListener(
+ listener: SmartspaceTargetListener,
+ smartspaceDataPlugin: BcSmartspaceDataPlugin?
+ ) {
+ execution.assertIsMainThread()
+ smartspaceDataPlugin?.unregisterListener(listener)
+ listeners.remove(listener)
+ disconnect()
+ }
+
+ private fun reloadSmartspace() {
+ session?.requestSmartspaceUpdate()
+ }
+
+ private fun onTargetsAvailableUnfiltered(targets: List<SmartspaceTarget>) {
+ unfilteredListeners.forEach { it.onSmartspaceTargetsUpdated(targets) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 333fc194b288..708f137017ca 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -22,6 +22,7 @@ import android.view.MotionEvent
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.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.media.controls.ui.MediaHost
import com.android.systemui.shade.ShadeViewController
import javax.inject.Provider
@@ -43,6 +44,15 @@ abstract class BaseCommunalViewModel(
communalInteractor.onSceneChanged(scene)
}
+ /**
+ * Updates the transition state of the hub [SceneTransitionLayout].
+ *
+ * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ */
+ fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+ communalInteractor.setTransitionState(transitionState)
+ }
+
// TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block
// touches anymore.
/** Called when a touch is received outside the edge swipe area when hub mode is closed. */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 7b94fc182fe2..573a748b4290 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -76,6 +76,10 @@ constructor(
Intent(applicationContext, WidgetPickerActivity::class.java)
)
},
+ onEditDone = {
+ // TODO(b/315154364): in a separate change, lock the device and transition to GH
+ finish()
+ }
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
index 7ac1cc796d4b..9d4ed20ca582 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
@@ -25,11 +25,15 @@ import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
+
import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.Utils;
import com.android.systemui.CoreStartable;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent;
@@ -43,6 +47,7 @@ import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.condition.ConditionalCoreStartable;
@@ -195,34 +200,70 @@ public class DreamHomeControlsComplication implements Complication {
private final ActivityStarter mActivityStarter;
private final Context mContext;
+ private final ConfigurationController mConfigurationController;
private final ControlsComponent mControlsComponent;
private final UiEventLogger mUiEventLogger;
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onUiModeChanged() {
+ reloadResources();
+ }
+ };
+
@Inject
DreamHomeControlsChipViewController(
@Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
ActivityStarter activityStarter,
Context context,
+ ConfigurationController configurationController,
ControlsComponent controlsComponent,
UiEventLogger uiEventLogger) {
super(view);
mActivityStarter = activityStarter;
mContext = context;
+ mConfigurationController = configurationController;
mControlsComponent = controlsComponent;
mUiEventLogger = uiEventLogger;
}
@Override
protected void onViewAttached() {
- mView.setImageResource(mControlsComponent.getTileImageId());
- mView.setContentDescription(mContext.getString(mControlsComponent.getTileTitleId()));
+ reloadResources();
mView.setOnClickListener(this::onClickHomeControls);
+ mConfigurationController.addCallback(mConfigurationListener);
}
@Override
- protected void onViewDetached() {}
+ protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
+ }
+
+ private void reloadResources() {
+ final String title = getControlsTitle();
+ if (title != null) {
+ mView.setContentDescription(title);
+ }
+ mView.setImageResource(mControlsComponent.getTileImageId());
+ mView.setImageTintList(Utils.getColorAttr(mContext, android.R.attr.textColorPrimary));
+ final Drawable background = mView.getBackground();
+ if (background != null) {
+ background.setTintList(
+ Utils.getColorAttr(mContext, com.android.internal.R.attr.colorSurface));
+ }
+ }
+
+ @Nullable
+ private String getControlsTitle() {
+ try {
+ return mContext.getString(mControlsComponent.getTileTitleId());
+ } catch (Resources.NotFoundException e) {
+ return null;
+ }
+ }
private void onClickHomeControls(View v) {
if (DEBUG) Log.d(TAG, "home controls complication tapped");
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
index 08d0595eba23..b6dcfcbfad56 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
@@ -24,9 +24,8 @@ import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.widget.ImageView;
-import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
import com.android.systemui.complication.DreamHomeControlsComplication;
+import com.android.systemui.res.R;
import com.android.systemui.shared.shadow.DoubleShadowIconDrawable;
import com.android.systemui.shared.shadow.DoubleShadowTextHelper;
@@ -98,7 +97,7 @@ public interface DreamHomeControlsComplicationComponent {
@DreamHomeControlsComplicationScope
@Named(DREAM_HOME_CONTROLS_BACKGROUND_DRAWABLE)
static Drawable providesHomeControlsBackground(Context context, Resources resources) {
- final Drawable background = new DoubleShadowIconDrawable(createShadowInfo(
+ return new DoubleShadowIconDrawable(createShadowInfo(
resources,
R.dimen.dream_overlay_bottom_affordance_key_text_shadow_radius,
R.dimen.dream_overlay_bottom_affordance_key_text_shadow_dx,
@@ -117,11 +116,6 @@ public interface DreamHomeControlsComplicationComponent {
R.dimen.dream_overlay_bottom_affordance_width),
resources.getDimensionPixelSize(R.dimen.dream_overlay_bottom_affordance_inset)
);
-
- background.setTintList(
- Utils.getColorAttr(context, com.android.internal.R.attr.colorSurface));
-
- return background;
}
private static DoubleShadowTextHelper.ShadowInfo createShadowInfo(Resources resources,
diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
index 65d44957222a..3a927396527c 100644
--- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
+++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
@@ -63,6 +63,7 @@ interface BaseComposeFacade {
activity: ComponentActivity,
viewModel: BaseCommunalViewModel,
onOpenWidgetPicker: () -> Unit,
+ onEditDone: () -> Unit,
)
/** Create a [View] to represent [viewModel] on screen. */
diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
index 63b01edb01fa..0daa058720ba 100644
--- a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt
@@ -35,23 +35,22 @@ import java.util.concurrent.Executor
import javax.inject.Inject
/** Dialog to select contrast options */
-class ContrastDialogDelegate @Inject constructor(
- private val sysuiDialogFactory : SystemUIDialog.Factory,
+class ContrastDialogDelegate
+@Inject
+constructor(
+ private val sysuiDialogFactory: SystemUIDialog.Factory,
@Main private val mainExecutor: Executor,
private val uiModeManager: UiModeManager,
private val userTracker: UserTracker,
private val secureSettings: SecureSettings,
) : SystemUIDialog.Delegate, UiModeManager.ContrastChangeListener {
- override fun createDialog(): SystemUIDialog {
- return sysuiDialogFactory.create(this)
- }
-
@VisibleForTesting lateinit var contrastButtons: Map<Int, FrameLayout>
lateinit var dialogView: View
@VisibleForTesting var initialContrast: Float = fromContrastLevel(CONTRAST_LEVEL_STANDARD)
- override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ override fun createDialog(): SystemUIDialog {
+ val dialog = sysuiDialogFactory.create(this)
dialogView = dialog.layoutInflater.inflate(R.layout.contrast_dialog, null)
with(dialog) {
setView(dialogView)
@@ -67,12 +66,16 @@ class ContrastDialogDelegate @Inject constructor(
}
setPositiveButton(com.android.settingslib.R.string.done) { _, _ -> dialog.dismiss() }
}
+
+ return dialog
+ }
+
+ override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
contrastButtons =
mapOf(
- CONTRAST_LEVEL_STANDARD to dialogView.requireViewById(
- R.id.contrast_button_standard),
- CONTRAST_LEVEL_MEDIUM to dialogView.requireViewById(R.id.contrast_button_medium),
- CONTRAST_LEVEL_HIGH to dialogView.requireViewById(R.id.contrast_button_high)
+ CONTRAST_LEVEL_STANDARD to dialog.requireViewById(R.id.contrast_button_standard),
+ CONTRAST_LEVEL_MEDIUM to dialog.requireViewById(R.id.contrast_button_medium),
+ CONTRAST_LEVEL_HIGH to dialog.requireViewById(R.id.contrast_button_high)
)
contrastButtons.forEach { (contrastLevel, contrastButton) ->
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index d5b95d6721f9..5ec51f4c3dad 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -16,6 +16,12 @@
package com.android.systemui.flags
+import com.android.server.notification.Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS
+import com.android.server.notification.Flags.FLAG_POLITE_NOTIFICATIONS
+import com.android.server.notification.Flags.FLAG_VIBRATE_WHILE_UNLOCKED
+import com.android.server.notification.Flags.crossAppPoliteNotifications
+import com.android.server.notification.Flags.politeNotifications
+import com.android.server.notification.Flags.vibrateWhileUnlocked
import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.dagger.SysUISingleton
@@ -36,5 +42,14 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha
val keyguardBottomAreaRefactor = FlagToken(
FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor())
KeyguardShadeMigrationNssl.token dependsOn keyguardBottomAreaRefactor
+
+ val crossAppPoliteNotifToken =
+ FlagToken(FLAG_CROSS_APP_POLITE_NOTIFICATIONS, crossAppPoliteNotifications())
+ val politeNotifToken = FlagToken(FLAG_POLITE_NOTIFICATIONS, politeNotifications())
+ crossAppPoliteNotifToken dependsOn politeNotifToken
+
+ val vibrateWhileUnlockedToken =
+ FlagToken(FLAG_VIBRATE_WHILE_UNLOCKED, vibrateWhileUnlocked())
+ vibrateWhileUnlockedToken dependsOn politeNotifToken
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
index ae3b501d3006..e96660fe4f79 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
@@ -25,7 +25,7 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.Compile
import com.android.systemui.util.asIndenting
-import com.android.systemui.util.withIncreasedIndent
+import com.android.systemui.util.printCollection
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -59,10 +59,8 @@ abstract class FlagDependenciesBase(
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.asIndenting().run {
- println("allDependencies: ${allDependencies.size}")
- withIncreasedIndent { allDependencies.forEach(::println) }
- println("unmetDependencies: ${unmetDependencies.size}")
- withIncreasedIndent { unmetDependencies.forEach(::println) }
+ printCollection("allDependencies", allDependencies)
+ printCollection("unmetDependencies", unmetDependencies)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b753ff742100..b1d4587c20d8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -111,7 +111,7 @@ object Flags {
// TODO(b/301955929)
@JvmField
val NOTIF_LS_BACKGROUND_THREAD =
- unreleasedFlag("notification_lockscreen_mgr_bg_thread", teamfood = true)
+ releasedFlag("notification_lockscreen_mgr_bg_thread")
// 200 - keyguard/lockscreen
// ** Flag retired **
diff --git a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
index ae67e60b75f7..4d89a826b60a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
@@ -79,6 +79,22 @@ object RefactorFlagUtils {
check(!isEnabled) { "Legacy code path not supported when $flagName is enabled." }
/**
+ * Called to ensure the new code is only run when the flag is enabled. This will throw an
+ * exception if the flag is disabled to ensure that the refactor author catches issues in
+ * testing.
+ *
+ * Example usage:
+ * ```
+ * public void setSomeNewController(SomeController someController) {
+ * SomeRefactor.assertInNewMode();
+ * mSomeController = someController;
+ * }
+ * ````
+ */
+ inline fun assertInNewMode(isEnabled: Boolean, flagName: Any) =
+ check(isEnabled) { "New code path not supported when $flagName is disabled." }
+
+ /**
* This will [Log.wtf] with the given message, assuming [ASSERT_TAG] is loggable at that level.
* This means an engineer can prevent this from crashing by running the command:
* ```
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 33dd3d9bea16..edf964815ca1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -35,7 +35,7 @@ import static android.view.WindowManager.TransitionFlags;
import static android.view.WindowManager.TransitionOldType;
import static android.view.WindowManager.TransitionType;
-import static com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER;
+import static com.android.systemui.Flags.refactorGetCurrentUser;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -609,7 +609,7 @@ public class KeyguardService extends Service {
public void setCurrentUser(int userId) {
trace("Deprecated/NOT USED: setCurrentUser userId=" + userId);
checkPermission();
- if (!mFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (!refactorGetCurrentUser()) {
mKeyguardViewMediator.setCurrentUser(userId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b7260f2b2b94..d7a1906f68e4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -38,7 +38,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER;
+import static com.android.systemui.Flags.refactorGetCurrentUser;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -141,6 +141,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
@@ -616,7 +617,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
public void onUserSwitching(int userId) {
if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
synchronized (KeyguardViewMediator.this) {
- if (mFeatureFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (refactorGetCurrentUser()) {
notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
}
resetKeyguardDonePendingLocked();
@@ -1319,6 +1320,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
private SelectedUserInteractor mSelectedUserInteractor;
+ private KeyguardInteractor mKeyguardInteractor;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
@@ -1400,7 +1402,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
SystemPropertiesHelper systemPropertiesHelper,
Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ KeyguardInteractor keyguardInteractor) {
mContext = context;
mUserTracker = userTracker;
mFalsingCollector = falsingCollector;
@@ -1441,6 +1444,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}));
mDozeParameters = dozeParameters;
mSelectedUserInteractor = selectedUserInteractor;
+ mKeyguardInteractor = keyguardInteractor;
mStatusBarStateController = statusBarStateController;
statusBarStateController.addCallback(this);
@@ -1498,7 +1502,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- if (!mFeatureFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (!refactorGetCurrentUser()) {
KeyguardUpdateMonitor.setCurrentUser(mUserTracker.getUserId());
}
@@ -2618,6 +2622,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
setPendingLock(false); // user may have authenticated during the screen off animation
handleHide();
+ mKeyguardInteractor.keyguardDoneAnimationsFinished();
mUpdateMonitor.clearFingerprintRecognizedWhenKeyguardDone(currentUser);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 331d892304b3..3925dd1620b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -52,6 +52,7 @@ import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager;
import com.android.systemui.keyguard.data.quickaffordance.KeyguardDataQuickAffordanceModule;
import com.android.systemui.keyguard.data.repository.KeyguardFaceAuthModule;
import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
@@ -154,7 +155,8 @@ public class KeyguardModule {
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
SystemPropertiesHelper systemPropertiesHelper,
Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ KeyguardInteractor keyguardInteractor) {
return new KeyguardViewMediator(
context,
uiEventLogger,
@@ -199,7 +201,8 @@ public class KeyguardModule {
dreamingToLockscreenTransitionViewModel,
systemPropertiesHelper,
wmLockscreenVisibilityManager,
- selectedUserInteractor);
+ selectedUserInteractor,
+ keyguardInteractor);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index eceaf6c3c4fd..4d60dd0bea62 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -187,7 +187,8 @@ constructor(
faceManager?.sensorPropertiesInternal?.firstOrNull()?.supportsFaceDetection ?: false
private val _isAuthRunning = MutableStateFlow(false)
- override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning
+ override val isAuthRunning: StateFlow<Boolean>
+ get() = _isAuthRunning
private val keyguardSessionId: InstanceId?
get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)
@@ -253,13 +254,6 @@ constructor(
)
.andAllFlows("canFaceAuthRun", faceAuthLog)
.flowOn(backgroundDispatcher)
- .onEach {
- faceAuthLogger.canFaceAuthRunChanged(it)
- if (!it) {
- // Cancel currently running auth if any of the gating checks are false.
- cancel()
- }
- }
.stateIn(applicationScope, SharingStarted.Eagerly, false)
// Face detection can run only when lockscreen bypass is enabled
@@ -287,12 +281,9 @@ constructor(
)
.andAllFlows("canFaceDetectRun", faceDetectLog)
.flowOn(backgroundDispatcher)
- .onEach {
- if (!it) {
- cancelDetection()
- }
- }
.stateIn(applicationScope, SharingStarted.Eagerly, false)
+ observeFaceAuthGatingChecks()
+ observeFaceDetectGatingChecks()
observeFaceAuthResettingConditions()
listenForSchedulingWatchdog()
processPendingAuthRequests()
@@ -313,14 +304,14 @@ constructor(
}
private fun observeFaceAuthResettingConditions() {
- // Clear auth status when keyguard is going away or when the user is switching or device
- // starts going to sleep.
+ // Clear auth status when keyguard done animations finished or when the user is switching
+ // or device starts going to sleep.
merge(
powerInteractor.isAsleep,
if (featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
keyguardTransitionInteractor.isInTransitionToState(KeyguardState.GONE)
} else {
- keyguardRepository.isKeyguardGoingAway
+ keyguardRepository.keyguardDoneAnimationsFinished.map { true }
},
userRepository.selectedUser.map {
it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS
@@ -347,6 +338,17 @@ constructor(
pendingAuthenticateRequest.value = null
}
+ private fun observeFaceDetectGatingChecks() {
+ canRunDetection
+ .onEach {
+ if (!it) {
+ cancelDetection()
+ }
+ }
+ .flowOn(mainDispatcher)
+ .launchIn(applicationScope)
+ }
+
private fun isUdfps() =
deviceEntryFingerprintAuthRepository.availableFpSensorType.map {
it == BiometricType.UNDER_DISPLAY_FINGERPRINT
@@ -405,6 +407,20 @@ constructor(
)
}
+ private fun observeFaceAuthGatingChecks() {
+ canRunFaceAuth
+ .onEach {
+ faceAuthLogger.canFaceAuthRunChanged(it)
+ if (!it) {
+ // Cancel currently running auth if any of the gating checks are false.
+ faceAuthLogger.cancellingFaceAuth()
+ cancel()
+ }
+ }
+ .flowOn(mainDispatcher)
+ .launchIn(applicationScope)
+ }
+
private val faceAuthCallback =
object : FaceManager.AuthenticationCallback() {
override fun onAuthenticationFailed() {
@@ -539,7 +555,7 @@ constructor(
authenticate(it.uiEvent, it.fallbackToDetection)
}
}
- .flowOn(backgroundDispatcher)
+ .flowOn(mainDispatcher)
.launchIn(applicationScope)
}
@@ -635,7 +651,6 @@ constructor(
override fun cancel() {
if (authCancellationSignal == null) return
- faceAuthLogger.cancellingFaceAuth()
authCancellationSignal?.cancel()
cancelNotReceivedHandlerJob?.cancel()
cancelNotReceivedHandlerJob =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index 96386f3dc596..9a13558d3327 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
/** Encapsulates state about device entry fingerprint auth mechanism. */
@@ -61,6 +62,9 @@ interface DeviceEntryFingerprintAuthRepository {
/** Provide the current status of fingerprint authentication. */
val authenticationStatus: Flow<FingerprintAuthenticationStatus>
+
+ /** Indicates whether to update the side fingerprint sensor indicator visibility. */
+ val shouldUpdateIndicatorVisibility: Flow<Boolean>
}
/**
@@ -256,6 +260,37 @@ constructor(
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
+ override val shouldUpdateIndicatorVisibility: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val sendShouldUpdateIndicatorVisibility =
+ { shouldUpdateIndicatorVisibility: Boolean ->
+ trySendWithFailureLogging(
+ shouldUpdateIndicatorVisibility,
+ TAG,
+ "Error sending shouldUpdateIndicatorVisibility " +
+ "$shouldUpdateIndicatorVisibility"
+ )
+ }
+
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ sendShouldUpdateIndicatorVisibility(true)
+ }
+ override fun onStrongAuthStateChanged(userId: Int) {
+ sendShouldUpdateIndicatorVisibility(true)
+ }
+ }
+ sendShouldUpdateIndicatorVisibility(false)
+ keyguardUpdateMonitor.registerCallback(callback)
+ awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
+ }
+ .flowOn(mainDispatcher)
+ .shareIn(scope, started = SharingStarted.WhileSubscribed(), replay = 1)
+
companion object {
const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index b51edab6dfe8..31ef100abbcb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -160,6 +160,9 @@ interface KeyguardRepository {
/** Last point that [KeyguardRootView] was tapped */
val lastRootViewTapPosition: MutableStateFlow<Point?>
+ /** Is the ambient indication area visible? */
+ val ambientIndicationVisible: MutableStateFlow<Boolean>
+
/** Observable for the [StatusBarState] */
val statusBarState: StateFlow<StatusBarState>
@@ -189,6 +192,17 @@ interface KeyguardRepository {
/** Observable updated when keyguardDone should be called either now or soon. */
val keyguardDone: Flow<KeyguardDone>
+ /**
+ * Emits after the keyguard is done animating away.
+ *
+ * TODO(b/278086361): Remove once KEYGUARD_WM_STATE_REFACTOR flag is removed.
+ */
+ @Deprecated(
+ "Use KeyguardTransitionInteractor flows instead. The closest match for " +
+ "'keyguardDoneAnimationsFinished' is when the GONE transition is finished."
+ )
+ val keyguardDoneAnimationsFinished: Flow<Unit>
+
/** Receive whether clock should be centered on lockscreen. */
val clockShouldBeCentered: Flow<Boolean>
@@ -236,6 +250,17 @@ interface KeyguardRepository {
suspend fun setKeyguardDone(keyguardDoneType: KeyguardDone)
fun setClockShouldBeCentered(shouldBeCentered: Boolean)
+
+ /**
+ * Updates signal that the keyguard done animations are finished
+ *
+ * TODO(b/278086361): Remove once KEYGUARD_WM_STATE_REFACTOR flag is removed.
+ */
+ @Deprecated(
+ "Use KeyguardTransitionInteractor flows instead. The closest match for " +
+ "'keyguardDoneAnimationsFinished' is when the GONE transition is finished."
+ )
+ fun keyguardDoneAnimationsFinished()
}
/** Encapsulates application state for the keyguard. */
@@ -266,6 +291,11 @@ constructor(
_keyguardDone.emit(keyguardDoneType)
}
+ override val keyguardDoneAnimationsFinished: MutableSharedFlow<Unit> = MutableSharedFlow()
+ override fun keyguardDoneAnimationsFinished() {
+ keyguardDoneAnimationsFinished.tryEmit(Unit)
+ }
+
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
_animateBottomAreaDozingTransitions.asStateFlow()
@@ -423,6 +453,8 @@ constructor(
override val lastRootViewTapPosition: MutableStateFlow<Point?> = MutableStateFlow(null)
+ override val ambientIndicationVisible: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
override val isDreamingWithOverlay: Flow<Boolean> =
conflatedCallbackFlow {
val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
new file mode 100644
index 000000000000..de15fd6a958f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import android.content.Context
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/**
+ * Encapsulates business logic for device entry events that impact the side fingerprint sensor
+ * overlay.
+ */
+@SysUISingleton
+class DeviceEntrySideFpsOverlayInteractor
+@Inject
+constructor(
+ @Application private val context: Context,
+ deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ alternateBouncerInteractor: AlternateBouncerInteractor,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+) {
+
+ init {
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, TAG)
+ }
+
+ private val showIndicatorForPrimaryBouncer: Flow<Boolean> =
+ merge(
+ primaryBouncerInteractor.isShowing,
+ primaryBouncerInteractor.startingToHide,
+ primaryBouncerInteractor.startingDisappearAnimation.filterNotNull(),
+ deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it }
+ )
+ .map { shouldShowIndicatorForPrimaryBouncer() }
+
+ private val showIndicatorForAlternateBouncer: Flow<Boolean> =
+ alternateBouncerInteractor.isVisible
+
+ /**
+ * Indicates whether the primary or alternate bouncers request showing the side fingerprint
+ * sensor indicator.
+ */
+ val showIndicatorForDeviceEntry: Flow<Boolean> =
+ combine(showIndicatorForPrimaryBouncer, showIndicatorForAlternateBouncer) {
+ showForPrimaryBouncer,
+ showForAlternateBouncer ->
+ showForPrimaryBouncer || showForAlternateBouncer
+ }
+
+ private fun shouldShowIndicatorForPrimaryBouncer(): Boolean {
+ val sfpsEnabled: Boolean =
+ context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
+ val sfpsDetectionRunning = keyguardUpdateMonitor.isFingerprintDetectionRunning
+ val isUnlockingWithFpAllowed = keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
+ return primaryBouncerInteractor.isBouncerShowing() &&
+ sfpsEnabled &&
+ sfpsDetectionRunning &&
+ isUnlockingWithFpAllowed &&
+ !primaryBouncerInteractor.isAnimatingAway()
+ }
+
+ companion object {
+ private const val TAG = "DeviceEntrySideFpsOverlayInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index c12efe875b0b..21651ba2cc2b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -174,6 +174,9 @@ constructor(
/** Last point that [KeyguardRootView] view was tapped */
val lastRootViewTapPosition: Flow<Point?> = repository.lastRootViewTapPosition.asStateFlow()
+ /** Is the ambient indication area visible? */
+ val ambientIndicationVisible: Flow<Boolean> = repository.ambientIndicationVisible.asStateFlow()
+
/** Whether the primary bouncer is showing or not. */
val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerShow
@@ -311,6 +314,14 @@ constructor(
repository.lastRootViewTapPosition.value = point
}
+ fun setAmbientIndicationVisible(isVisible: Boolean) {
+ repository.ambientIndicationVisible.value = isVisible
+ }
+
+ fun keyguardDoneAnimationsFinished() {
+ repository.keyguardDoneAnimationsFinished()
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index fb20000471a2..e3f47397eca3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -31,7 +31,6 @@ import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
@@ -72,7 +71,6 @@ constructor(
private val context: Context,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
- @Background private val backgroundDispatcher: CoroutineDispatcher,
private val repository: DeviceEntryFaceAuthRepository,
private val primaryBouncerInteractor: Lazy<PrimaryBouncerInteractor>,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
@@ -109,7 +107,6 @@ constructor(
fallbackToDetect = false
)
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
alternateBouncerInteractor.isVisible
@@ -121,7 +118,6 @@ constructor(
fallbackToDetect = false
)
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
merge(
@@ -150,7 +146,6 @@ constructor(
fallbackToDetect = true
)
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
deviceEntryFingerprintAuthRepository.isLockedOut
@@ -163,7 +158,6 @@ constructor(
}
}
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
// User switching should stop face auth and then when it is complete we should trigger face
@@ -187,7 +181,6 @@ constructor(
)
}
}
- .flowOn(backgroundDispatcher)
.launchIn(applicationScope)
}
@@ -302,7 +295,6 @@ constructor(
trustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, userInfo.id)
}
}
- .flowOn(backgroundDispatcher)
.onEach { (isAuthenticated, _) ->
listeners.forEach { it.onAuthenticatedChanged(isAuthenticated) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
index 560e4adf956a..9a6dca3c4958 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
@@ -21,6 +21,7 @@ import android.graphics.Point
import com.android.systemui.CoreStartable
import com.android.systemui.Flags
import com.android.systemui.biometrics.SideFpsController
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.view.SideFpsProgressBar
@@ -46,6 +47,7 @@ constructor(
private val viewModel: SideFpsProgressBarViewModel,
private val view: SideFpsProgressBar,
@Application private val applicationScope: CoroutineScope,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
private val sfpsController: dagger.Lazy<SideFpsController>,
private val logger: SideFpsLogger,
private val commandRegistry: CommandRegistry,
@@ -109,12 +111,14 @@ constructor(
view.updateView(visible, location, length, thickness, rotation)
// We have to hide the SFPS indicator as the progress bar will
// be shown at the same location
- if (visible) {
- logger.hidingSfpsIndicator()
- sfpsController.get().hideIndicator()
- } else if (fpDetectRunning) {
- logger.showingSfpsIndicator()
- sfpsController.get().showIndicator()
+ if (!SideFpsControllerRefactor.isEnabled) {
+ if (visible) {
+ logger.hidingSfpsIndicator()
+ sfpsController.get().hideIndicator()
+ } else if (fpDetectRunning) {
+ logger.showingSfpsIndicator()
+ sfpsController.get().showIndicator()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index acfd3b0bcf57..24240dfe7402 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -30,6 +30,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants
+import com.android.systemui.util.kotlin.logD
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -58,11 +59,14 @@ constructor(
observer =
PreviewLifecycleObserver(
- renderer,
applicationScope,
mainDispatcher,
+ renderer,
::destroyObserver,
)
+
+ logD(TAG) { "Created observer $observer" }
+
// Destroy any previous renderer associated with this token.
activePreviews[renderer.id]?.let { destroyObserver(it) }
activePreviews[renderer.id] = observer
@@ -80,6 +84,8 @@ constructor(
observer,
)
)
+ // NOTE: The process on the other side can retain messenger indefinitely.
+ // (e.g. GC might not trigger and cleanup the reference)
val msg = Message.obtain()
msg.replyTo = messenger
result.putParcelable(KEY_PREVIEW_CALLBACK, msg)
@@ -99,57 +105,84 @@ constructor(
}
}
- private class PreviewLifecycleObserver(
- private val renderer: KeyguardPreviewRenderer,
- private val scope: CoroutineScope,
- private val mainDispatcher: CoroutineDispatcher,
- private val requestDestruction: (PreviewLifecycleObserver) -> Unit,
- ) : Handler.Callback, IBinder.DeathRecipient {
+ companion object {
+ internal const val TAG = "KeyguardRemotePreviewManager"
+ @VisibleForTesting const val KEY_PREVIEW_SURFACE_PACKAGE = "surface_package"
+ @VisibleForTesting const val KEY_PREVIEW_CALLBACK = "callback"
+ }
+}
- private var isDestroyedOrDestroying = false
+/**
+ * Handles messages from the other process and handles cleanup.
+ *
+ * NOTE: The other process might hold on to reference of this class indefinitely. It's entirely
+ * possible that GC won't trigger and we'll leak this for all times even if [onDestroy] was called.
+ * This helps make sure no non-Singleton objects are retained beyond destruction to prevent leaks.
+ */
+@VisibleForTesting(VisibleForTesting.PRIVATE)
+class PreviewLifecycleObserver(
+ private val scope: CoroutineScope,
+ private val mainDispatcher: CoroutineDispatcher,
+ renderer: KeyguardPreviewRenderer,
+ onDestroy: (PreviewLifecycleObserver) -> Unit,
+) : Handler.Callback, IBinder.DeathRecipient {
+
+ private var isDestroyedOrDestroying = false
+ // These two are null after destruction
+ @VisibleForTesting var renderer: KeyguardPreviewRenderer?
+ @VisibleForTesting var onDestroy: ((PreviewLifecycleObserver) -> Unit)?
+
+ init {
+ this.renderer = renderer
+ this.onDestroy = onDestroy
+ }
- override fun handleMessage(message: Message): Boolean {
- if (isDestroyedOrDestroying) {
- return true
- }
+ override fun handleMessage(message: Message): Boolean {
+ if (isDestroyedOrDestroying) {
+ return true
+ }
- when (message.what) {
- KeyguardPreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
- message.data.getString(KeyguardPreviewConstants.KEY_SLOT_ID)?.let { slotId ->
- renderer.onSlotSelected(slotId = slotId)
- }
+ when (message.what) {
+ KeyguardPreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
+ message.data.getString(KeyguardPreviewConstants.KEY_SLOT_ID)?.let { slotId ->
+ checkNotNull(renderer).onSlotSelected(slotId = slotId)
}
- KeyguardPreviewConstants.MESSAGE_ID_HIDE_SMART_SPACE -> {
- renderer.hideSmartspace(
+ }
+ KeyguardPreviewConstants.MESSAGE_ID_HIDE_SMART_SPACE -> {
+ checkNotNull(renderer)
+ .hideSmartspace(
message.data.getBoolean(KeyguardPreviewConstants.KEY_HIDE_SMART_SPACE)
)
- }
- else -> requestDestruction(this)
}
-
- return true
+ else -> checkNotNull(onDestroy).invoke(this)
}
- override fun binderDied() {
- requestDestruction(this)
+ return true
+ }
+
+ override fun binderDied() {
+ onDestroy?.invoke(this)
+ }
+
+ fun onDestroy(): Pair<IBinder?, Int>? {
+ if (isDestroyedOrDestroying) {
+ return null
}
- fun onDestroy(): Pair<IBinder?, Int>? {
- if (isDestroyedOrDestroying) {
- return null
- }
+ logD(TAG) { "Destroying $this" }
- isDestroyedOrDestroying = true
- val hostToken = renderer.hostToken
+ isDestroyedOrDestroying = true
+ return renderer?.let { rendererToDestroy ->
+ this.renderer = null
+ this.onDestroy = null
+ val hostToken = rendererToDestroy.hostToken
hostToken?.unlinkToDeath(this, 0)
- scope.launch(mainDispatcher) { renderer.destroy() }
- return renderer.id
+ scope.launch(mainDispatcher) { rendererToDestroy.destroy() }
+ rendererToDestroy.id
}
}
companion object {
private const val TAG = "KeyguardRemotePreviewManager"
- @VisibleForTesting const val KEY_PREVIEW_SURFACE_PACKAGE = "surface_package"
- @VisibleForTesting const val KEY_PREVIEW_CALLBACK = "callback"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 1d4520ff8f03..26dace00ad76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -180,7 +180,9 @@ constructor(
goneToAodTransitionViewModel
.enterFromTopTranslationY(enterFromTopAmount)
.onStart { emit(0f) },
- occludedToLockscreenTransitionViewModel.lockscreenTranslationY,
+ occludedToLockscreenTransitionViewModel.lockscreenTranslationY.onStart {
+ emit(0f)
+ },
) {
keyguardTransitionY,
burnInTranslationY,
@@ -193,6 +195,7 @@ constructor(
occludedToLockscreenTransitionTranslationY
}
}
+ .distinctUntilChanged()
val translationX: Flow<Float> = burnIn().map { it.translationX.toFloat() }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
index 2d0712c7f9cc..1dbf1f14b569 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Point
+import androidx.annotation.VisibleForTesting
import androidx.core.animation.doOnEnd
import com.android.systemui.Flags
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
@@ -213,4 +214,9 @@ constructor(
}
}
}
+
+ @VisibleForTesting
+ fun setVisible(isVisible: Boolean) {
+ _visible.value = isVisible
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index 14d4b6800b0a..c87fd14a943d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -119,7 +119,7 @@ internal constructor(
::AnimatingColorTransition
)
- val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_secondary95)
+ val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_neutral20)
val surfaceColor =
animatingColorTransitionFactory(bgColor, ::surfaceFromScheme) { surfaceColor ->
val colorList = ColorStateList.valueOf(surfaceColor)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 9cdf85794088..992eeca77e54 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -40,6 +40,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -76,6 +77,7 @@ import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import java.util.Locale
import java.util.TreeMap
+import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
@@ -102,6 +104,7 @@ constructor(
private val activityStarter: ActivityStarter,
private val systemClock: SystemClock,
@Main executor: DelayableExecutor,
+ @Background private val bgExecutor: Executor,
private val mediaManager: MediaDataManager,
configurationController: ConfigurationController,
falsingManager: FalsingManager,
@@ -1030,7 +1033,7 @@ constructor(
desiredHostState?.let {
if (this.desiredLocation != desiredLocation) {
// Only log an event when location changes
- logger.logCarouselPosition(desiredLocation)
+ bgExecutor.execute { logger.logCarouselPosition(desiredLocation) }
}
// This is a hosting view, let's remeasure our players
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 8d1ff98a5bba..62c7343d3fe5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -31,7 +31,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_B
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IMMERSIVE_MODE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
@@ -322,7 +321,6 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
.setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isWindowVisible())
.setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
allowSystemGestureIgnoringBarVisibility())
- .setFlag(SYSUI_STATE_IMMERSIVE_MODE, isImmersiveMode())
.commitUpdate(mDisplayId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 9846f4b6c980..e660b97b5c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -69,7 +69,6 @@ import androidx.annotation.DimenRes;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -81,6 +80,7 @@ import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputChannelCompat;
@@ -1113,6 +1113,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
// Capture inputs
mInputMonitor.pilferPointers();
if (mBackAnimation != null) {
+ mBackAnimation.onPilferPointers();
// Notify FalsingManager that an intentional gesture has occurred.
mFalsingManager.isFalseTouch(BACK_GESTURE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 270bfbe4274d..0e7e69b97d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -263,7 +263,11 @@ constructor(
* If the shortcut entry `android:enabled` is set to `true`, the shortcut will be visible in the
* Widget Picker to all users.
*/
+ // TODO(b/316332684)
+ @Suppress("UNREACHABLE_CODE")
fun setNoteTaskShortcutEnabled(value: Boolean, user: UserHandle) {
+ return // shortcut should not be enabled until additional features are implemented.
+
if (!userManager.isUserUnlocked(user)) {
debugLog { "setNoteTaskShortcutEnabled call but user locked: user=$user" }
return
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index 6d55d0549d2e..de490a58a498 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -27,7 +27,6 @@ import android.os.UserManager
import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.res.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -43,6 +42,7 @@ import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEnabledKey
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.res.R
import com.android.systemui.stylus.StylusManager
import dagger.Lazy
import java.util.concurrent.Executor
@@ -100,7 +100,8 @@ constructor(
isEnabled &&
isUserUnlocked &&
isDefaultNotesAppSet &&
- (isConfigSelected || isStylusEverUsed)
+ isConfigSelected &&
+ isStylusEverUsed
) {
val contentDescription = ContentDescription.Resource(pickerNameResourceId)
val icon = Icon.Resource(pickerIconResourceId, contentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt
index fdc70a83e8b1..76ef8a2b813c 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogControllerV2.kt
@@ -278,7 +278,12 @@ class PrivacyDialogControllerV2(
d.setShowForAllUsers(true)
d.addOnDismissListener(onDialogDismissed)
if (view != null) {
- dialogLaunchAnimator.showFromView(d, view)
+ val controller = getPrivacyDialogController(view)
+ if (controller == null) {
+ d.show()
+ } else {
+ dialogLaunchAnimator.show(d, controller)
+ }
} else {
d.show()
}
@@ -291,6 +296,13 @@ class PrivacyDialogControllerV2(
}
}
+ private fun getPrivacyDialogController(source: View): DialogLaunchAnimator.Controller? {
+ val delegate = DialogLaunchAnimator.Controller.fromView(source) ?: return null
+ return object : DialogLaunchAnimator.Controller by delegate {
+ override fun shouldAnimateExit() = false
+ }
+ }
+
/** Dismisses the dialog */
fun dismissDialog() {
dialog?.dismiss()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/OWNERS b/packages/SystemUI/src/com/android/systemui/qs/OWNERS
new file mode 100644
index 000000000000..45a4b5035c45
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/OWNERS
@@ -0,0 +1,10 @@
+set noparent
+
+# Bug component: 78010
+
+apotapov@google.com
+asc@google.com
+bhnm@google.com
+kozynski@google.com
+ostonge@google.com
+pixel@google.com \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 6c930b1f3d17..3e50dd35749f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -43,6 +43,9 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.animation.DisappearParameters;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -50,9 +53,6 @@ import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;
-import kotlin.Unit;
-import kotlin.jvm.functions.Function1;
-
/**
* Controller for QSPanel views.
*
@@ -232,7 +232,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
mQsTileRevealController.updateRevealedTiles(tiles);
}
boolean shouldChange = false;
- if (tiles.size() == mRecords.size()) {
+ if (tiles.size() <= mRecords.size()) {
int i = 0;
for (QSTile tile : tiles) {
if (tile != mRecords.get(i).tile) {
@@ -241,6 +241,17 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
}
i++;
}
+
+ // If the first tiles are the same as the new ones, remove any extras.
+ if (!shouldChange) {
+ while (i < mRecords.size()) {
+ QSPanelControllerBase.TileRecord record = mRecords.get(i);
+ mView.removeTile(record);
+ record.tile.removeCallback(record.callback);
+ i++;
+ }
+ mCachedSpecs = getTilesSpecs();
+ }
} else {
shouldChange = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
index b50798e59953..4bad45f19673 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
@@ -20,6 +20,7 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
import com.android.systemui.qs.pipeline.data.repository.DefaultTilesQSHostRepository
import com.android.systemui.qs.pipeline.data.repository.DefaultTilesRepository
import com.android.systemui.qs.pipeline.data.repository.InstalledTilesComponentRepository
@@ -39,14 +40,17 @@ import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
+import dagger.multibindings.Multibinds
-@Module(includes = [QSAutoAddModule::class])
+@Module(includes = [QSAutoAddModule::class, RestoreProcessorsModule::class])
abstract class QSPipelineModule {
/** Implementation for [TileSpecRepository] */
@Binds
abstract fun provideTileSpecRepository(impl: TileSpecSettingsRepository): TileSpecRepository
+ @Multibinds abstract fun provideRestoreProcessors(): Set<RestoreProcessor>
+
@Binds
abstract fun provideDefaultTilesRepository(
impl: DefaultTilesQSHostRepository
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.kt
new file mode 100644
index 000000000000..e970c84d166f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/RestoreProcessorsModule.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.qs.pipeline.dagger
+
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
+import com.android.systemui.qs.pipeline.data.restoreprocessors.WorkTileRestoreProcessor
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+
+@Module
+interface RestoreProcessorsModule {
+
+ @Binds
+ @IntoSet
+ fun bindWorkTileRestoreProcessor(impl: WorkTileRestoreProcessor): RestoreProcessor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt
new file mode 100644
index 000000000000..8f7de1976b36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessor.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.qs.pipeline.data.model
+
+/**
+ * Perform processing of the [RestoreData] before or after it's applied to repositories.
+ *
+ * The order in which the restore processors are applied in not deterministic.
+ *
+ * In order to declare a restore processor, add it in [RestoreProcessingModule] using
+ *
+ * ```
+ * @Binds
+ * @IntoSet
+ * ``
+ */
+interface RestoreProcessor {
+
+ /** Should be called before applying the restore to the necessary repositories */
+ suspend fun preProcessRestore(restoreData: RestoreData) {}
+
+ /** Should be called after requesting the repositories to update. */
+ suspend fun postProcessRestore(restoreData: RestoreData) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt
index 7998dfbe3f92..d40f3f4db5f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt
@@ -20,9 +20,8 @@ import android.util.SparseArray
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.pipeline.data.model.RestoreData
import com.android.systemui.qs.pipeline.shared.TileSpec
-import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
-import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.Flow
/** Repository to track what QS tiles have been auto-added */
interface AutoAddRepository {
@@ -49,8 +48,9 @@ interface AutoAddRepository {
@SysUISingleton
class AutoAddSettingRepository
@Inject
-constructor(private val userAutoAddRepositoryFactory: UserAutoAddRepository.Factory) :
- AutoAddRepository {
+constructor(
+ private val userAutoAddRepositoryFactory: UserAutoAddRepository.Factory,
+) : AutoAddRepository {
private val userAutoAddRepositories = SparseArray<UserAutoAddRepository>()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt
index 6cee1161a104..e718eea09665 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt
@@ -10,6 +10,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.repository.QSSettingsRestoredRepository.Companion.BUFFER_CAPACITY
import com.android.systemui.qs.pipeline.data.repository.TilesSettingConverter.toTilesList
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import javax.inject.Inject
@@ -28,6 +29,14 @@ import kotlinx.coroutines.flow.shareIn
/** Provides restored data (from Backup and Restore) for Quick Settings pipeline */
interface QSSettingsRestoredRepository {
val restoreData: Flow<RestoreData>
+
+ companion object {
+ // This capacity is the number of restore data that we will keep buffered in the shared
+ // flow. It is unlikely that at any given time there would be this many restores being
+ // processed by consumers, but just in case that a couple of users are restored at the
+ // same time and they need to be replayed for the consumers of the flow.
+ const val BUFFER_CAPACITY = 10
+ }
}
@SysUISingleton
@@ -86,11 +95,6 @@ constructor(
private companion object {
private const val TAG = "QSSettingsRestoredBroadcastRepository"
- // This capacity is the number of restore data that we will keep buffered in the shared
- // flow. It is unlikely that at any given time there would be this many restores being
- // processed by consumers, but just in case that a couple of users are restored at the
- // same time and they need to be replayed for the consumers of the flow.
- private const val BUFFER_CAPACITY = 10
private val INTENT_FILTER = IntentFilter(Intent.ACTION_SETTING_RESTORED)
private const val TILES_SETTING = Settings.Secure.QS_TILES
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt
new file mode 100644
index 000000000000..7376aa90883f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessor.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.qs.pipeline.data.restoreprocessors
+
+import android.os.UserHandle
+import android.util.SparseIntArray
+import androidx.annotation.GuardedBy
+import androidx.core.util.getOrDefault
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.data.model.RestoreData
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
+import com.android.systemui.qs.pipeline.data.repository.QSSettingsRestoredRepository
+import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.WorkModeTile
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+
+/**
+ * Processor for restore data for work tile.
+ *
+ * It will indicate when auto-add tracking may be removed for a user. This may be necessary if the
+ * tile will be destroyed due to being not available, but needs to be added once work profile is
+ * enabled (after restore), in the same position as it was in the restored data.
+ */
+@SysUISingleton
+class WorkTileRestoreProcessor @Inject constructor() : RestoreProcessor {
+
+ @GuardedBy("lastRestorePosition") private val lastRestorePosition = SparseIntArray()
+
+ private val _removeTrackingForUser =
+ MutableSharedFlow<Int>(extraBufferCapacity = QSSettingsRestoredRepository.BUFFER_CAPACITY)
+
+ /**
+ * Flow indicating that we may need to remove auto-add tracking for the work tile for a given
+ * user.
+ */
+ fun removeTrackingForUser(userHandle: UserHandle): Flow<Unit> {
+ return _removeTrackingForUser.filter { it == userHandle.identifier }.map {}
+ }
+
+ override suspend fun postProcessRestore(restoreData: RestoreData) {
+ if (TILE_SPEC in restoreData.restoredTiles) {
+ synchronized(lastRestorePosition) {
+ lastRestorePosition.put(
+ restoreData.userId,
+ restoreData.restoredTiles.indexOf(TILE_SPEC)
+ )
+ }
+ _removeTrackingForUser.emit(restoreData.userId)
+ }
+ }
+
+ fun pollLastPosition(userId: Int): Int {
+ return synchronized(lastRestorePosition) {
+ lastRestorePosition.getOrDefault(userId, TileSpecRepository.POSITION_AT_END).also {
+ lastRestorePosition.delete(userId)
+ }
+ }
+ }
+
+ companion object {
+ private val TILE_SPEC = TileSpec.create(WorkModeTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
index 5e3c34841c50..b22119966460 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
@@ -17,8 +17,10 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
import android.content.pm.UserInfo
+import android.os.UserHandle
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.data.restoreprocessors.WorkTileRestoreProcessor
import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
@@ -28,6 +30,8 @@ import com.android.systemui.settings.UserTracker
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.flow.merge
/**
* [AutoAddable] for [WorkModeTile.TILE_SPEC].
@@ -36,17 +40,37 @@ import kotlinx.coroutines.flow.Flow
* signal to remove it if there is not.
*/
@SysUISingleton
-class WorkTileAutoAddable @Inject constructor(private val userTracker: UserTracker) : AutoAddable {
+class WorkTileAutoAddable
+@Inject
+constructor(
+ private val userTracker: UserTracker,
+ private val workTileRestoreProcessor: WorkTileRestoreProcessor,
+) : AutoAddable {
private val spec = TileSpec.create(WorkModeTile.TILE_SPEC)
override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
- return conflatedCallbackFlow {
+ val removeTrackingDueToRestore: Flow<AutoAddSignal> =
+ workTileRestoreProcessor.removeTrackingForUser(UserHandle.of(userId)).mapNotNull {
+ val profiles = userTracker.userProfiles
+ if (profiles.any { it.id == userId } && !profiles.any { it.isManagedProfile }) {
+ // Only remove auto-added if there are no managed profiles for this user
+ AutoAddSignal.RemoveTracking(spec)
+ } else {
+ null
+ }
+ }
+ val signalsFromCallback = conflatedCallbackFlow {
fun maybeSend(profiles: List<UserInfo>) {
if (profiles.any { it.id == userId }) {
// We are looking at the profiles of the correct user.
if (profiles.any { it.isManagedProfile }) {
- trySend(AutoAddSignal.Add(spec))
+ trySend(
+ AutoAddSignal.Add(
+ spec,
+ workTileRestoreProcessor.pollLastPosition(userId),
+ )
+ )
} else {
trySend(AutoAddSignal.Remove(spec))
}
@@ -65,6 +89,7 @@ class WorkTileAutoAddable @Inject constructor(private val userTracker: UserTrack
awaitClose { userTracker.removeCallback(callback) }
}
+ return merge(removeTrackingDueToRestore, signalsFromCallback)
}
override val autoAddTracking = AutoAddTracking.Always
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
index b74739322fcd..cde38359a871 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
@@ -103,6 +103,10 @@ constructor(
qsPipelineLogger.logTileAutoRemoved(userId, signal.spec)
repository.unmarkTileAdded(userId, signal.spec)
}
+ is AutoAddSignal.RemoveTracking -> {
+ qsPipelineLogger.logTileUnmarked(userId, signal.spec)
+ repository.unmarkTileAdded(userId, signal.spec)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt
index 9844903eff26..a5be14ec3776 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractor.kt
@@ -3,14 +3,15 @@ package com.android.systemui.qs.pipeline.domain.interactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.qs.pipeline.data.model.RestoreProcessor
import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
import com.android.systemui.qs.pipeline.data.repository.QSSettingsRestoredRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
+import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.take
@@ -33,6 +34,8 @@ constructor(
private val tileSpecRepository: TileSpecRepository,
private val autoAddRepository: AutoAddRepository,
private val qsSettingsRestoredRepository: QSSettingsRestoredRepository,
+ private val restoreProcessors: Set<@JvmSuppressWildcards RestoreProcessor>,
+ private val qsPipelineLogger: QSPipelineLogger,
@Application private val applicationScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) {
@@ -40,14 +43,30 @@ constructor(
@OptIn(ExperimentalCoroutinesApi::class)
fun start() {
applicationScope.launch(backgroundDispatcher) {
- qsSettingsRestoredRepository.restoreData.flatMapConcat { data ->
- autoAddRepository.autoAddedTiles(data.userId)
- .take(1)
- .map { tiles -> data to tiles }
- }.collect { (restoreData, autoAdded) ->
- tileSpecRepository.reconcileRestore(restoreData, autoAdded)
- autoAddRepository.reconcileRestore(restoreData)
- }
+ qsSettingsRestoredRepository.restoreData
+ .flatMapConcat { data ->
+ autoAddRepository.autoAddedTiles(data.userId).take(1).map { tiles ->
+ data to tiles
+ }
+ }
+ .collect { (restoreData, autoAdded) ->
+ restoreProcessors.forEach {
+ it.preProcessRestore(restoreData)
+ qsPipelineLogger.logRestoreProcessorApplied(
+ it::class.simpleName,
+ QSPipelineLogger.RestorePreprocessorStep.PREPROCESSING,
+ )
+ }
+ tileSpecRepository.reconcileRestore(restoreData, autoAdded)
+ autoAddRepository.reconcileRestore(restoreData)
+ restoreProcessors.forEach {
+ it.postProcessRestore(restoreData)
+ qsPipelineLogger.logRestoreProcessorApplied(
+ it::class.simpleName,
+ QSPipelineLogger.RestorePreprocessorStep.POSTPROCESSING,
+ )
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
index ed7b8bd4c2f4..8263680d7fad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
@@ -34,4 +34,9 @@ sealed interface AutoAddSignal {
data class Remove(
override val spec: TileSpec,
) : AutoAddSignal
+
+ /** Signal for remove the auto-add marker from the tile, but not remove the tile */
+ data class RemoveTracking(
+ override val spec: TileSpec,
+ ) : AutoAddSignal
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
index 935d07229ae5..42bee3c8f877 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
@@ -22,8 +22,8 @@ class QSPipelineFlagsRepository @Inject constructor() {
AconfigFlags.FLAG_QS_NEW_PIPELINE
)
- fun assertNewTilesInLegacyMode() =
- RefactorFlagUtils.assertInLegacyMode(
+ fun assertNewTiles() =
+ RefactorFlagUtils.assertInNewMode(
AconfigFlags.qsNewTiles(),
AconfigFlags.FLAG_QS_NEW_TILES
)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index bca86c9ee8af..7d2c6c8f70fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -209,6 +209,18 @@ constructor(
)
}
+ fun logTileUnmarked(userId: Int, spec: TileSpec) {
+ tileAutoAddLogBuffer.log(
+ AUTO_ADD_TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = userId
+ str1 = spec.toString()
+ },
+ { "Tile $str1 unmarked as auto-added for user $int1" }
+ )
+ }
+
fun logSettingsRestored(restoreData: RestoreData) {
restoreLogBuffer.log(
RESTORE_TAG,
@@ -226,6 +238,21 @@ constructor(
)
}
+ fun logRestoreProcessorApplied(
+ restoreProcessorClassName: String?,
+ step: RestorePreprocessorStep,
+ ) {
+ restoreLogBuffer.log(
+ RESTORE_TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = restoreProcessorClassName
+ str2 = step.name
+ },
+ { "Restore $str2 processed by $str1" }
+ )
+ }
+
/** Reasons for destroying an existing tile. */
enum class TileDestroyedReason(val readable: String) {
TILE_REMOVED("Tile removed from current set"),
@@ -234,4 +261,9 @@ constructor(
EXISTING_TILE_NOT_AVAILABLE("Existing tile not available"),
TILE_NOT_PRESENT_IN_NEW_USER("Tile not present in new user"),
}
+
+ enum class RestorePreprocessorStep {
+ PREPROCESSING,
+ POSTPROCESSING
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 38bbce45e143..17e6375967fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -19,6 +19,7 @@ import android.util.Log;
import androidx.annotation.Nullable;
+import com.android.systemui.accessibility.qs.QSAccessibilityModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -41,7 +42,7 @@ import javax.inject.Provider;
* com.android.systemui.qs.tiles.DreamTile#TILE_SPEC})
*
* After, create or find an existing Module class to house the tile's binding method (e.g. {@link
- * com.android.systemui.accessibility.AccessibilityModule}). If creating a new module, add your
+ * QSAccessibilityModule}). If creating a new module, add your
* module to the SystemUI dagger graph by including it in an appropriate module.
*/
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index a4088f81f062..66da8bdd0311 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles
+import android.app.AlertDialog
import android.content.Intent
import android.os.Handler
import android.os.Looper
@@ -24,8 +25,11 @@ import android.text.TextUtils
import android.view.View
import android.widget.Switch
import androidx.annotation.VisibleForTesting
+import com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN
import com.android.internal.logging.MetricsLogger
import com.android.systemui.Flags.recordIssueQsTile
+import com.android.systemui.animation.DialogCuj
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
@@ -36,7 +40,12 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.res.R
+import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
class RecordIssueTile
@@ -50,7 +59,12 @@ constructor(
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
- qsLogger: QSLogger
+ qsLogger: QSLogger,
+ private val keyguardDismissUtil: KeyguardDismissUtil,
+ private val keyguardStateController: KeyguardStateController,
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val sysuiDialogFactory: SystemUIDialog.Factory,
+ private val userContextProvider: UserContextProvider,
) :
QSTileImpl<QSTile.BooleanState>(
host,
@@ -76,11 +90,41 @@ constructor(
handlesLongClick = false
}
- override fun handleClick(view: View?) {
- isRecording = !isRecording
+ @VisibleForTesting
+ public override fun handleClick(view: View?) {
+ if (isRecording) {
+ isRecording = false
+ } else {
+ mUiHandler.post { showPrompt(view) }
+ }
refreshState()
}
+ private fun showPrompt(view: View?) {
+ val dialog: AlertDialog =
+ RecordIssueDialogDelegate(sysuiDialogFactory, userContextProvider) {
+ isRecording = true
+ refreshState()
+ }
+ .createDialog()
+ val dismissAction =
+ ActivityStarter.OnDismissAction {
+ // We animate from the touched view only if we are not on the keyguard, given
+ // that if we are we will dismiss it which will also collapse the shade.
+ if (view != null && !keyguardStateController.isShowing) {
+ dialogLaunchAnimator.showFromView(
+ dialog,
+ view,
+ DialogCuj(CUJ_SHADE_DIALOG_OPEN, TILE_SPEC)
+ )
+ } else {
+ dialog.show()
+ }
+ false
+ }
+ keyguardDismissUtil.executeWhenUnlocked(dismissAction, false, true)
+ }
+
override fun getLongClickIntent(): Intent? = null
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
index 09d7a1f7142d..17b78ebf106c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
@@ -24,7 +24,7 @@ interface QSTileUserActionInteractor<DATA_TYPE> {
* [QSTileInput.data]. It's guaranteed that [QSTileInput.userId] is the same as the id passed to
* [QSTileDataInteractor] to get [QSTileInput.data].
*
- * It's safe to run long running computations inside this function in this.
+ * It's safe to run long running computations inside this function.
*/
@WorkerThread suspend fun handleInput(input: QSTileInput<DATA_TYPE>)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
new file mode 100644
index 000000000000..d0437a7210f1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.qs.tiles.base.viewmodel
+
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+
+/** Creates a [CoroutineScope] for the [QSTileViewModelImpl]. */
+class QSTileCoroutineScopeFactory
+@Inject
+constructor(@Application private val applicationScope: CoroutineScope) {
+
+ fun create(): CoroutineScope =
+ CoroutineScope(applicationScope.coroutineContext + SupervisorJob())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
index ae554d954580..ffa3b543736b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
@@ -82,6 +82,7 @@ sealed interface QSTileViewModelFactory<T> {
qsTileLogger,
systemClock,
backgroundDispatcher,
+ component.coroutineScope(),
)
}
}
@@ -101,6 +102,7 @@ sealed interface QSTileViewModelFactory<T> {
private val qsTileConfigProvider: QSTileConfigProvider,
private val systemClock: SystemClock,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val coroutineScopeFactory: QSTileCoroutineScopeFactory,
) : QSTileViewModelFactory<T> {
/**
@@ -130,6 +132,7 @@ sealed interface QSTileViewModelFactory<T> {
qsTileLogger,
systemClock,
backgroundDispatcher,
+ coroutineScopeFactory.create(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 9fe316f99136..45c6fffe6bd1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -39,7 +39,6 @@ import java.io.PrintWriter
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -82,7 +81,7 @@ class QSTileViewModelImpl<DATA_TYPE>(
private val qsTileLogger: QSTileLogger,
private val systemClock: SystemClock,
private val backgroundDispatcher: CoroutineDispatcher,
- private val tileScope: CoroutineScope = CoroutineScope(SupervisorJob()),
+ private val tileScope: CoroutineScope,
) : QSTileViewModel, Dumpable {
private val users: MutableStateFlow<UserHandle> =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
index 52e49f9d2653..382cfe267aae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
@@ -45,7 +45,7 @@ constructor(
) : QSFactory {
init {
- QSPipelineFlagsRepository.assertNewTilesInLegacyMode()
+ QSPipelineFlagsRepository.assertNewTiles()
for (viewModelTileSpec in tileMap.keys) {
require(qsTileConfigProvider.hasConfig(viewModelTileSpec)) {
"No config for $viewModelTileSpec"
@@ -56,7 +56,7 @@ constructor(
override fun createTile(tileSpec: String): QSTile? {
val viewModel: QSTileViewModel =
when (val spec = TileSpec.create(tileSpec)) {
- is TileSpec.CustomTileSpec -> createCustomTileViewModel(spec)
+ is TileSpec.CustomTileSpec -> null
is TileSpec.PlatformTileSpec -> tileMap[tileSpec]?.get()
is TileSpec.Invalid -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
index 4a34276671c1..b325b4daeb81 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles.di
+import android.content.Context
+import android.content.res.Resources.Theme
import com.android.systemui.qs.external.CustomTileStatePersister
import com.android.systemui.qs.external.CustomTileStatePersisterImpl
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
@@ -27,6 +29,7 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProviderImpl
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
import dagger.Binds
import dagger.Module
+import dagger.Provides
import dagger.multibindings.Multibinds
/** Module listing subcomponents */
@@ -57,4 +60,9 @@ interface QSTilesModule {
@Binds
fun bindCustomTileStatePersister(impl: CustomTileStatePersisterImpl): CustomTileStatePersister
+
+ companion object {
+
+ @Provides fun provideTilesTheme(context: Context): Theme = context.theme
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 2350b5dce8b8..9d214e7141a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -59,12 +59,12 @@ import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
import com.android.systemui.Prefs;
-import com.android.systemui.res.R;
import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wifitrackerlib.WifiEntry;
@@ -157,14 +157,6 @@ public class InternetDialog extends SystemUIDialog implements
// Wi-Fi scanning progress bar
protected boolean mIsProgressBarVisible;
- protected boolean mIsSearchingHidden;
- protected final Runnable mHideProgressBarRunnable = () -> {
- setProgressBarVisible(false);
- };
- protected Runnable mHideSearchingRunnable = () -> {
- mIsSearchingHidden = true;
- mInternetDialogSubTitle.setText(getSubtitleText());
- };
@Inject
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
@@ -285,8 +277,6 @@ public class InternetDialog extends SystemUIDialog implements
if (DEBUG) {
Log.d(TAG, "onStop");
}
- mHandler.removeCallbacks(mHideProgressBarRunnable);
- mHandler.removeCallbacks(mHideSearchingRunnable);
mMobileNetworkLayout.setOnClickListener(null);
mConnectedWifListLayout.setOnClickListener(null);
if (mSecondaryMobileNetworkLayout != null) {
@@ -335,7 +325,6 @@ public class InternetDialog extends SystemUIDialog implements
return;
}
- showProgressBar();
final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
final boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
@@ -641,8 +630,7 @@ public class InternetDialog extends SystemUIDialog implements
@Nullable
CharSequence getSubtitleText() {
- return mInternetDialogController.getSubtitleText(
- mIsProgressBarVisible && !mIsSearchingHidden);
+ return mInternetDialogController.getSubtitleText(mIsProgressBarVisible);
}
private Drawable getSignalStrengthDrawable(int subId) {
@@ -657,20 +645,6 @@ public class InternetDialog extends SystemUIDialog implements
return mInternetDialogController.getMobileNetworkSummary(subId);
}
- protected void showProgressBar() {
- if (!mInternetDialogController.isWifiEnabled()
- || mInternetDialogController.isDeviceLocked()) {
- setProgressBarVisible(false);
- return;
- }
- setProgressBarVisible(true);
- if (mConnectedWifiEntry != null || mWifiEntriesCount > 0) {
- mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS);
- } else if (!mIsSearchingHidden) {
- mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS);
- }
- }
-
private void setProgressBarVisible(boolean visible) {
if (mIsProgressBarVisible == visible) {
return;
@@ -823,6 +797,11 @@ public class InternetDialog extends SystemUIDialog implements
}
@Override
+ public void onWifiScan(boolean isScan) {
+ setProgressBarVisible(isScan);
+ }
+
+ @Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (mAlertDialog != null && !mAlertDialog.isShowing()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index f516f5521d25..592cb3b18e80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -75,7 +75,6 @@ import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.settingslib.wifi.WifiUtils;
import com.android.settingslib.wifi.dpp.WifiDppIntentHelper;
-import com.android.systemui.res.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -84,6 +83,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.LocationController;
@@ -1129,6 +1129,15 @@ public class InternetDialogController implements AccessPointController.AccessPoi
public void onSettingsActivityTriggered(Intent settingsIntent) {
}
+ @Override
+ public void onWifiScan(boolean isScan) {
+ if (!isWifiEnabled() || isDeviceLocked()) {
+ mCallback.onWifiScan(false);
+ return;
+ }
+ mCallback.onWifiScan(isScan);
+ }
+
private class InternetTelephonyCallback extends TelephonyCallback implements
TelephonyCallback.DataConnectionStateListener,
TelephonyCallback.DisplayInfoListener,
@@ -1372,6 +1381,8 @@ public class InternetDialogController implements AccessPointController.AccessPoi
void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
@Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries);
+
+ void onWifiScan(boolean isScan);
}
void makeOverlayToast(int stringId) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt
index cfb544226c83..9b8dba166274 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.airplane.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
@@ -27,18 +28,25 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [AirplaneModeTileModel] to [QSTileState]. */
-class AirplaneModeMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<AirplaneModeTileModel> {
+class AirplaneModeMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ val theme: Theme,
+) : QSTileDataToStateMapper<AirplaneModeTileModel> {
override fun map(config: QSTileConfig, data: AirplaneModeTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
val icon =
- Icon.Resource(
- if (data.isEnabled) {
- R.drawable.qs_airplane_icon_on
- } else {
- R.drawable.qs_airplane_icon_off
- },
+ Icon.Loaded(
+ resources.getDrawable(
+ if (data.isEnabled) {
+ R.drawable.qs_airplane_icon_on
+ } else {
+ R.drawable.qs_airplane_icon_off
+ },
+ theme,
+ ),
contentDescription = null
)
this.icon = { icon }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
index 63865777e14f..e075e76595d4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.alarm.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel
@@ -30,14 +31,18 @@ import java.util.TimeZone
import javax.inject.Inject
/** Maps [AlarmTileModel] to [QSTileState]. */
-class AlarmTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<AlarmTileModel> {
+class AlarmTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<AlarmTileModel> {
companion object {
val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E hh:mm a")
val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E HH:mm")
}
override fun map(config: QSTileConfig, data: AlarmTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
when (data) {
is AlarmTileModel.NextAlarmSet -> {
activationState = QSTileState.ActivationState.ACTIVE
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt
new file mode 100644
index 000000000000..1efbfd70fa98
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt
@@ -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.systemui.qs.tiles.impl.colorcorrection.domain
+
+import android.content.res.Resources
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** Maps [ColorCorrectionTileModel] to [QSTileState]. */
+class ColorCorrectionTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+) : QSTileDataToStateMapper<ColorCorrectionTileModel> {
+
+ override fun map(config: QSTileConfig, data: ColorCorrectionTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ val subtitleArray = resources.getStringArray(R.array.tile_states_color_correction)
+
+ if (data.isEnabled) {
+ activationState = QSTileState.ActivationState.ACTIVE
+ secondaryLabel = subtitleArray[2]
+ } else {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel = subtitleArray[1]
+ }
+ contentDescription = label
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt
new file mode 100644
index 000000000000..cd33d451ba81
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Observes color correction state changes providing the [ColorCorrectionTileModel]. */
+class ColorCorrectionTileDataInteractor
+@Inject
+constructor(
+ private val colorCorrectionRepository: ColorCorrectionRepository,
+) : QSTileDataInteractor<ColorCorrectionTileModel> {
+
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<ColorCorrectionTileModel> {
+ return colorCorrectionRepository.isEnabled(user).map { ColorCorrectionTileModel(it) }
+ }
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
new file mode 100644
index 000000000000..d1838029db4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+/** Handles color correction tile clicks. */
+class ColorCorrectionUserActionInteractor
+@Inject
+constructor(
+ private val colorCorrectionRepository: ColorCorrectionRepository,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<ColorCorrectionTileModel> {
+
+ override suspend fun handleInput(input: QSTileInput<ColorCorrectionTileModel>): Unit =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ colorCorrectionRepository.setIsEnabled(
+ !data.isEnabled,
+ user,
+ )
+ }
+ is QSTileUserAction.LongClick -> {
+ qsTileIntentUserActionHandler.handle(
+ action.view,
+ Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt
new file mode 100644
index 000000000000..66487e1bba60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection.domain.model
+
+/**
+ * Color correction tile model.
+ *
+ * @param isEnabled is true when the color correction is enabled;
+ */
+@JvmInline value class ColorCorrectionTileModel(val isEnabled: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
index 6d7d88fbfa79..92b0f3aa604d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
@@ -16,46 +16,103 @@
package com.android.systemui.qs.tiles.impl.custom.data.repository
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
import android.os.UserHandle
+import androidx.annotation.GuardedBy
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
-import com.android.systemui.qs.external.TileServiceManager
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileBoundScope
-import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileUser
+import com.android.systemui.qs.tiles.impl.di.QSTileScope
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.launch
interface CustomTilePackageUpdatesRepository {
- val packageChanges: Flow<Unit>
+ fun getPackageChangesForUser(user: UserHandle): Flow<Unit>
}
-@CustomTileBoundScope
+@QSTileScope
class CustomTilePackageUpdatesRepositoryImpl
@Inject
constructor(
- tileSpec: TileSpec.CustomTileSpec,
- @CustomTileUser user: UserHandle,
- serviceManager: TileServiceManager,
- defaultsRepository: CustomTileDefaultsRepository,
- @CustomTileBoundScope boundScope: CoroutineScope,
+ private val tileSpec: TileSpec.CustomTileSpec,
+ @Application private val context: Context,
+ @QSTileScope private val tileScope: CoroutineScope,
+ @Background private val backgroundCoroutineContext: CoroutineContext,
) : CustomTilePackageUpdatesRepository {
- override val packageChanges: Flow<Unit> =
+ @GuardedBy("perUserCache")
+ private val perUserCache: MutableMap<UserHandle, Flow<Unit>> = mutableMapOf()
+
+ override fun getPackageChangesForUser(user: UserHandle): Flow<Unit> =
+ synchronized(perUserCache) {
+ perUserCache.getOrPut(user) {
+ createPackageChangesFlowForUser(user)
+ .onCompletion {
+ // clear cache when nobody listens
+ synchronized(perUserCache) { perUserCache.remove(user) }
+ }
+ .flowOn(backgroundCoroutineContext)
+ .shareIn(tileScope, SharingStarted.WhileSubscribed())
+ }
+ }
+
+ @SuppressLint(
+ "MissingPermission", // android.permission.INTERACT_ACROSS_USERS_FULL
+ "UnspecifiedRegisterReceiverFlag",
+ "RegisterReceiverViaContext",
+ )
+ private fun createPackageChangesFlowForUser(user: UserHandle): Flow<Unit> =
ConflatedCallbackFlow.conflatedCallbackFlow {
- serviceManager.setTileChangeListener { changedComponentName ->
- if (changedComponentName == tileSpec.componentName) {
- trySend(Unit)
+ val receiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ launch { send(intent) }
+ }
}
+ context.registerReceiverAsUser(
+ receiver,
+ user,
+ INTENT_FILTER,
+ /* broadcastPermission = */ null,
+ /* scheduler = */ null,
+ )
+
+ awaitClose { context.unregisterReceiver(receiver) }
+ }
+ .filter { intent ->
+ intent ?: return@filter false
+ if (intent.action?.let(INTENT_FILTER::matchAction) != true) {
+ return@filter false
}
+ val changedComponentNames =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST)
+ changedComponentNames?.contains(tileSpec.componentName.packageName) == true
+ }
+ .map {}
+
+ private companion object {
+
+ val INTENT_FILTER =
+ IntentFilter().apply {
+ addDataScheme(IntentFilter.SCHEME_PACKAGE)
- awaitClose { serviceManager.setTileChangeListener(null) }
+ addAction(Intent.ACTION_PACKAGE_CHANGED)
}
- .onEach { defaultsRepository.requestNewDefaults(user, tileSpec.componentName, true) }
- .shareIn(boundScope, SharingStarted.WhileSubscribed())
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt
index d956fdebcd32..ba8b23ab795a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt
@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles.impl.custom.di
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileCoroutineScopeFactory
import com.android.systemui.qs.tiles.impl.custom.CustomTileInteractor
import com.android.systemui.qs.tiles.impl.custom.CustomTileMapper
import com.android.systemui.qs.tiles.impl.custom.CustomTileUserActionInteractor
@@ -26,13 +27,15 @@ import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefau
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepositoryImpl
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileRepository
import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileRepositoryImpl
-import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileBoundComponent
import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel
+import com.android.systemui.qs.tiles.impl.di.QSTileScope
import dagger.Binds
import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.CoroutineScope
/** Provides bindings for QSTile interfaces */
-@Module(subcomponents = [CustomTileBoundComponent::class])
+@Module
interface CustomTileModule {
@Binds
@@ -54,4 +57,13 @@ interface CustomTileModule {
): CustomTileDefaultsRepository
@Binds fun bindCustomTileRepository(impl: CustomTileRepositoryImpl): CustomTileRepository
+
+ companion object {
+
+ @Provides
+ @QSTileScope
+ fun provideCustomTileCoroutineScope(
+ scopeFactory: QSTileCoroutineScopeFactory
+ ): CoroutineScope = scopeFactory.create()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
index b3d916a86144..0ed46e73958d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles.impl.di
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import kotlinx.coroutines.CoroutineScope
/**
* Base QS tile component. It should be used with [QSTileScope] to create a custom tile scoped
@@ -32,4 +33,12 @@ interface QSTileComponent<T> {
fun userActionInteractor(): QSTileUserActionInteractor<T>
fun dataToStateMapper(): QSTileDataToStateMapper<T>
+
+ /**
+ * Use [com.android.systemui.qs.tiles.base.viewmodel.QSTileCoroutineScopeFactory] to create a
+ * [CoroutineScope] provided by this method. This enables you to use the same scope the
+ * [com.android.systemui.qs.tiles.viewmodel.QSTileViewModel] uses. This scope is cancelled when
+ * the view model is destroyed.
+ */
+ @QSTileScope fun coroutineScope(): CoroutineScope
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt
index 881a6bd156d2..1b3b5848a7ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.flashlight.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
@@ -27,18 +28,25 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [FlashlightTileModel] to [QSTileState]. */
-class FlashlightMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<FlashlightTileModel> {
+class FlashlightMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<FlashlightTileModel> {
override fun map(config: QSTileConfig, data: FlashlightTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
val icon =
- Icon.Resource(
- if (data.isEnabled) {
- R.drawable.qs_flashlight_icon_on
- } else {
- R.drawable.qs_flashlight_icon_off
- },
+ Icon.Loaded(
+ resources.getDrawable(
+ if (data.isEnabled) {
+ R.drawable.qs_flashlight_icon_on
+ } else {
+ R.drawable.qs_flashlight_icon_off
+ },
+ theme,
+ ),
contentDescription = null
)
this.icon = { icon }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt
index 7e7034d65efd..fe5445d00670 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.location.domain
import android.content.res.Resources
+import android.content.res.Resources.Theme
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
@@ -27,18 +28,25 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [LocationTileModel] to [QSTileState]. */
-class LocationTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<LocationTileModel> {
+class LocationTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<LocationTileModel> {
override fun map(config: QSTileConfig, data: LocationTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
val icon =
- Icon.Resource(
- if (data.isEnabled) {
- R.drawable.qs_location_icon_on
- } else {
- R.drawable.qs_location_icon_off
- },
+ Icon.Loaded(
+ resources.getDrawable(
+ if (data.isEnabled) {
+ R.drawable.qs_location_icon_on
+ } else {
+ R.drawable.qs_location_icon_off
+ },
+ theme,
+ ),
contentDescription = null
)
this.icon = { icon }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt
index 25b09131522b..df25600228a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt
@@ -27,20 +27,28 @@ import com.android.systemui.res.R
import javax.inject.Inject
/** Maps [DataSaverTileModel] to [QSTileState]. */
-class DataSaverTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<DataSaverTileModel> {
+class DataSaverTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+) : QSTileDataToStateMapper<DataSaverTileModel> {
override fun map(config: QSTileConfig, data: DataSaverTileModel): QSTileState =
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
with(data) {
+ val iconRes: Int
if (isEnabled) {
activationState = QSTileState.ActivationState.ACTIVE
- icon = { Icon.Resource(R.drawable.qs_data_saver_icon_on, null) }
+ iconRes = R.drawable.qs_data_saver_icon_on
secondaryLabel = resources.getStringArray(R.array.tile_states_saver)[2]
} else {
activationState = QSTileState.ActivationState.INACTIVE
- icon = { Icon.Resource(R.drawable.qs_data_saver_icon_off, null) }
+ iconRes = R.drawable.qs_data_saver_icon_off
secondaryLabel = resources.getStringArray(R.array.tile_states_saver)[1]
}
+ val loadedIcon =
+ Icon.Loaded(resources.getDrawable(iconRes, theme), contentDescription = null)
+ icon = { loadedIcon }
contentDescription = label
supportedActions =
setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
index 3f30c75a6b6a..ffef2b6ecfb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles.impl.uimodenight.domain
import android.app.UiModeManager
import android.content.res.Resources
+import android.content.res.Resources.Theme
import android.text.TextUtils
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Main
@@ -31,15 +32,19 @@ import java.time.format.DateTimeFormatter
import javax.inject.Inject
/** Maps [UiModeNightTileModel] to [QSTileState]. */
-class UiModeNightTileMapper @Inject constructor(@Main private val resources: Resources) :
- QSTileDataToStateMapper<UiModeNightTileModel> {
+class UiModeNightTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<UiModeNightTileModel> {
companion object {
val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("hh:mm a")
val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
}
override fun map(config: QSTileConfig, data: UiModeNightTileModel): QSTileState =
with(data) {
- QSTileState.build(resources, config.uiConfig) {
+ QSTileState.build(resources, theme, config.uiConfig) {
var shouldSetSecondaryLabel = false
if (isPowerSave) {
@@ -116,8 +121,9 @@ class UiModeNightTileMapper @Inject constructor(@Main private val resources: Res
if (activationState == QSTileState.ActivationState.ACTIVE)
R.drawable.qs_light_dark_theme_icon_on
else R.drawable.qs_light_dark_theme_icon_off
- val iconResource = Icon.Resource(iconRes, null)
- icon = { iconResource }
+ val loadedIcon =
+ Icon.Loaded(resources.getDrawable(iconRes, theme), contentDescription = null)
+ icon = { loadedIcon }
supportedActions =
if (activationState == QSTileState.ActivationState.UNAVAILABLE)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
index 23e0cb66bb6a..be1b7404314f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.viewmodel
import android.content.res.Resources
+import android.content.res.Resources.Theme
import android.service.quicksettings.Tile
import android.view.View
import android.widget.Switch
@@ -47,14 +48,17 @@ data class QSTileState(
fun build(
resources: Resources,
+ theme: Theme,
config: QSTileUIConfig,
build: Builder.() -> Unit
- ): QSTileState =
- build(
- { Icon.Resource(config.iconRes, null) },
+ ): QSTileState {
+ val iconDrawable = resources.getDrawable(config.iconRes, theme)
+ return build(
+ { Icon.Loaded(iconDrawable, null) },
resources.getString(config.labelRes),
build,
)
+ }
fun build(icon: () -> Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState =
Builder(icon, label).apply(build).build()
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
new file mode 100644
index 000000000000..5bf44fa5b143
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -0,0 +1,113 @@
+/*
+ * 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.recordissue
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.app.BroadcastOptions
+import android.app.PendingIntent
+import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.os.Bundle
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.WindowManager
+import android.widget.Button
+import android.widget.PopupMenu
+import android.widget.Switch
+import com.android.systemui.res.R
+import com.android.systemui.screenrecord.RecordingService
+import com.android.systemui.screenrecord.ScreenRecordingAudioSource
+import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+class RecordIssueDialogDelegate(
+ private val factory: SystemUIDialog.Factory,
+ private val userContextProvider: UserContextProvider,
+ private val onStarted: Runnable
+) : SystemUIDialog.Delegate {
+
+ @SuppressLint("UseSwitchCompatOrMaterialCode") private lateinit var screenRecordSwitch: Switch
+ private lateinit var issueTypeButton: Button
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ dialog.apply {
+ setView(LayoutInflater.from(context).inflate(R.layout.record_issue_dialog, null))
+ setTitle(context.getString(R.string.qs_record_issue_label))
+ setIcon(R.drawable.qs_record_issue_icon_off)
+ setNegativeButton(R.string.cancel) { _, _ -> dismiss() }
+ setPositiveButton(R.string.qs_record_issue_start) { _, _ ->
+ onStarted.run()
+ if (screenRecordSwitch.isChecked) {
+ requestScreenCapture()
+ }
+ dismiss()
+ }
+ }
+ }
+
+ override fun createDialog(): SystemUIDialog = factory.create(this)
+
+ override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ dialog.apply {
+ window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
+ window?.setGravity(Gravity.CENTER)
+
+ screenRecordSwitch = requireViewById(R.id.screenrecord_switch)
+ issueTypeButton = requireViewById(R.id.issue_type_button)
+ issueTypeButton.setOnClickListener { onIssueTypeClicked(context) }
+ }
+ }
+
+ private fun onIssueTypeClicked(context: Context) {
+ val selectedCategory = issueTypeButton.text.toString()
+ val popupMenu = PopupMenu(context, issueTypeButton)
+
+ context.resources.getStringArray(R.array.qs_record_issue_types).forEachIndexed { i, cat ->
+ popupMenu.menu.add(0, 0, i, cat).apply {
+ setIcon(R.drawable.arrow_pointing_down)
+ if (selectedCategory != cat) {
+ iconTintList = ColorStateList.valueOf(Color.TRANSPARENT)
+ }
+ }
+ }
+ popupMenu.apply {
+ setOnMenuItemClickListener {
+ issueTypeButton.text = it.title
+ true
+ }
+ setForceShowIcon(true)
+ show()
+ }
+ }
+
+ private fun requestScreenCapture() =
+ PendingIntent.getForegroundService(
+ userContextProvider.userContext,
+ RecordingService.REQUEST_CODE,
+ RecordingService.getStartIntent(
+ userContextProvider.userContext,
+ Activity.RESULT_OK,
+ ScreenRecordingAudioSource.NONE.ordinal,
+ false,
+ null
+ ),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index d42fde617394..47518bbee57a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -44,6 +44,11 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICA
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.printSection
+import com.android.systemui.util.println
+import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -94,6 +99,15 @@ constructor(
}
}
+ override fun dump(pw: PrintWriter, args: Array<out String>) =
+ pw.asIndenting().run {
+ printSection("SceneContainerFlags") {
+ println("isEnabled", flags.isEnabled())
+ printSection("requirementDescription") { println(flags.requirementDescription()) }
+ println("flexiNotifsEnabled", flags.flexiNotifsEnabled())
+ }
+ }
+
/** Updates the visibility of the scene container. */
private fun hydrateVisibility() {
applicationScope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index 8a93ef65b4bf..d3459b109d79 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -32,6 +32,7 @@ import javax.inject.Inject
* TODO(b/200063118): Make this class the one source of truth for the state of panel expansion.
*/
@SysUISingleton
+@Deprecated("Use ShadeInteractor instead")
class ShadeExpansionStateManager @Inject constructor() {
private val expansionListeners = CopyOnWriteArrayList<ShadeExpansionListener>()
@@ -49,6 +50,7 @@ class ShadeExpansionStateManager @Inject constructor() {
*
* @see #addExpansionListener
*/
+ @Deprecated("Use ShadeInteractor instead")
fun addExpansionListener(listener: ShadeExpansionListener): ShadeExpansionChangeEvent {
expansionListeners.add(listener)
return ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
@@ -60,6 +62,7 @@ class ShadeExpansionStateManager @Inject constructor() {
}
/** Adds a listener that will be notified when the panel state has changed. */
+ @Deprecated("Use ShadeInteractor instead")
fun addStateListener(listener: ShadeStateListener) {
stateListeners.add(listener)
}
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
index c59ef2632f15..d26fded19cc1 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
@@ -59,6 +59,11 @@ abstract class SmartspaceModule {
* The BcSmartspaceDataPlugin for the standalone weather.
*/
const val WEATHER_SMARTSPACE_DATA_PLUGIN = "weather_smartspace_data_plugin"
+
+ /**
+ * The BcSmartspaceDataProvider for the glanceable hub.
+ */
+ const val GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN = "glanceable_hub_smartspace_data_plugin"
}
@BindsOptionalOf
@@ -78,4 +83,8 @@ abstract class SmartspaceModule {
abstract fun bindSmartspacePrecondition(
lockscreenPrecondition: LockscreenPrecondition?
): SmartspacePrecondition?
+
+ @BindsOptionalOf
+ @Named(GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN)
+ abstract fun optionalBcSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
}
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
index 2fc0ec290a90..095d30ef55df 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
@@ -19,9 +19,9 @@ package com.android.systemui.smartspace.data.repository
import android.app.smartspace.SmartspaceTarget
import android.os.Parcelable
import android.widget.RemoteViews
+import com.android.systemui.communal.smartspace.CommunalSmartspaceController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.BcSmartspaceDataPlugin
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -32,37 +32,37 @@ interface SmartspaceRepository {
/** Whether [RemoteViews] are passed through smartspace targets. */
val isSmartspaceRemoteViewsEnabled: Boolean
- /** Smartspace targets for the lockscreen surface. */
- val lockscreenSmartspaceTargets: Flow<List<SmartspaceTarget>>
+ /** Smartspace targets for the communal surface. */
+ val communalSmartspaceTargets: Flow<List<SmartspaceTarget>>
}
@SysUISingleton
class SmartspaceRepositoryImpl
@Inject
constructor(
- private val lockscreenSmartspaceController: LockscreenSmartspaceController,
+ private val communalSmartspaceController: CommunalSmartspaceController,
) : SmartspaceRepository, BcSmartspaceDataPlugin.SmartspaceTargetListener {
override val isSmartspaceRemoteViewsEnabled: Boolean
get() = android.app.smartspace.flags.Flags.remoteViews()
- private val _lockscreenSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
+ private val _communalSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
MutableStateFlow(emptyList())
- override val lockscreenSmartspaceTargets: Flow<List<SmartspaceTarget>> =
- _lockscreenSmartspaceTargets
+ override val communalSmartspaceTargets: Flow<List<SmartspaceTarget>> =
+ _communalSmartspaceTargets
.onStart {
- lockscreenSmartspaceController.addListener(listener = this@SmartspaceRepositoryImpl)
+ communalSmartspaceController.addListener(listener = this@SmartspaceRepositoryImpl)
}
.onCompletion {
- lockscreenSmartspaceController.removeListener(
+ communalSmartspaceController.removeListener(
listener = this@SmartspaceRepositoryImpl
)
}
override fun onSmartspaceTargetsUpdated(targetsNullable: MutableList<out Parcelable>?) {
targetsNullable?.let { targets ->
- _lockscreenSmartspaceTargets.value = targets.filterIsInstance<SmartspaceTarget>()
+ _communalSmartspaceTargets.value = targets.filterIsInstance<SmartspaceTarget>()
}
- ?: run { _lockscreenSmartspaceTargets.value = emptyList() }
+ ?: run { _communalSmartspaceTargets.value = emptyList() }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index d23c85a6d796..cfbd015f1cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -18,16 +18,16 @@ package com.android.systemui.statusbar;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Handler;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
import java.util.stream.Stream;
@@ -46,13 +46,12 @@ public abstract class AlertingNotificationManager {
protected int mMinimumDisplayTime;
protected int mStickyForSomeTimeAutoDismissTime;
protected int mAutoDismissTime;
- @VisibleForTesting
- public Handler mHandler;
+ private DelayableExecutor mExecutor;
- public AlertingNotificationManager(HeadsUpManagerLogger logger, @Main Handler handler,
- SystemClock systemClock) {
+ public AlertingNotificationManager(HeadsUpManagerLogger logger,
+ SystemClock systemClock, @Main DelayableExecutor executor) {
mLogger = logger;
- mHandler = handler;
+ mExecutor = executor;
mSystemClock = systemClock;
}
@@ -264,6 +263,7 @@ public abstract class AlertingNotificationManager {
public long mEarliestRemovalTime;
@Nullable protected Runnable mRemoveAlertRunnable;
+ @Nullable private Runnable mCancelRemoveAlertRunnable;
public void setEntry(@NonNull final NotificationEntry entry) {
setEntry(entry, () -> removeAlertEntry(entry.getKey()));
@@ -291,13 +291,15 @@ public abstract class AlertingNotificationManager {
if (updatePostTime) {
mPostTime = Math.max(mPostTime, now);
}
- removeAutoRemovalCallbacks("updateEntry (will be rescheduled)");
- if (!isSticky()) {
- final long finishTime = calculateFinishTime();
- final long timeLeft = Math.max(finishTime - now, mMinimumDisplayTime);
- mHandler.postDelayed(mRemoveAlertRunnable, timeLeft);
+ if (isSticky()) {
+ removeAutoRemovalCallbacks("updateEntry (sticky)");
+ return;
}
+
+ final long finishTime = calculateFinishTime();
+ final long timeLeft = Math.max(finishTime - now, mMinimumDisplayTime);
+ scheduleAutoRemovalCallback(timeLeft, "updateEntry (not sticky)");
}
/**
@@ -340,21 +342,50 @@ public abstract class AlertingNotificationManager {
* Clear any pending removal runnables.
*/
public void removeAutoRemovalCallbacks(@Nullable String reason) {
- if (mRemoveAlertRunnable != null) {
+ final boolean removed = removeAutoRemovalCallbackInternal();
+
+ if (removed) {
mLogger.logAutoRemoveCanceled(mEntry, reason);
- mHandler.removeCallbacks(mRemoveAlertRunnable);
}
}
+ private void scheduleAutoRemovalCallback(long delayMillis, @NonNull String reason) {
+ if (mRemoveAlertRunnable == null) {
+ Log.wtf(TAG, "scheduleAutoRemovalCallback with no callback set");
+ return;
+ }
+
+ final boolean removed = removeAutoRemovalCallbackInternal();
+
+ if (removed) {
+ mLogger.logAutoRemoveRescheduled(mEntry, delayMillis, reason);
+ } else {
+ mLogger.logAutoRemoveScheduled(mEntry, delayMillis, reason);
+ }
+
+
+ mCancelRemoveAlertRunnable = mExecutor.executeDelayed(mRemoveAlertRunnable,
+ delayMillis);
+ }
+
+ private boolean removeAutoRemovalCallbackInternal() {
+ final boolean scheduled = (mCancelRemoveAlertRunnable != null);
+
+ if (scheduled) {
+ mCancelRemoveAlertRunnable.run();
+ mCancelRemoveAlertRunnable = null;
+ }
+
+ return scheduled;
+ }
+
/**
* Remove the alert at the earliest allowed removal time.
*/
public void removeAsSoonAsPossible() {
if (mRemoveAlertRunnable != null) {
- removeAutoRemovalCallbacks("removeAsSoonAsPossible (will be rescheduled)");
-
final long timeLeft = mEarliestRemovalTime - mSystemClock.elapsedRealtime();
- mHandler.postDelayed(mRemoveAlertRunnable, timeLeft);
+ scheduleAutoRemovalCallback(timeLeft, "removeAsSoonAsPossible");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
index 490994d805fe..fc474d2a1307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
@@ -89,5 +89,12 @@ interface AccessPointController {
* "wifi_start_connect_ssid" set as an extra
*/
fun onSettingsActivityTriggered(settingsIntent: Intent?)
+
+ /**
+ * Called whenever a Wi-Fi scan is triggered.
+ *
+ * @param isScan Whether Wi-Fi scan is triggered or not.
+ */
+ fun onWifiScan(isScan: Boolean)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
index 91ca148c93c9..3a31851bcb4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
@@ -213,6 +213,12 @@ public class AccessPointControllerImpl implements AccessPointController,
}
}
+ private void fireWifiScanCallback(boolean isScan) {
+ for (AccessPointCallback callback : mCallbacks) {
+ callback.onWifiScan(isScan);
+ }
+ }
+
void dump(PrintWriter pw) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
ipw.println("AccessPointControllerImpl:");
@@ -240,6 +246,14 @@ public class AccessPointControllerImpl implements AccessPointController,
}
@Override
+ public void onWifiEntriesChanged(@WifiPickerTracker.WifiEntriesChangedReason int reason) {
+ onWifiEntriesChanged();
+ if (reason == WifiPickerTracker.WIFI_ENTRIES_CHANGED_REASON_SCAN_RESULTS) {
+ fireWifiScanCallback(false /* isScan */);
+ }
+ }
+
+ @Override
public void onNumSavedNetworksChanged() {
// Do nothing
}
@@ -249,6 +263,11 @@ public class AccessPointControllerImpl implements AccessPointController,
// Do nothing
}
+ @Override
+ public void onScanRequested() {
+ fireWifiScanCallback(true /* isScan */);
+ }
+
private final WifiEntry.ConnectCallback mConnectCallback = new WifiEntry.ConnectCallback() {
@Override
public void onConnectResult(int status) {
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 92391e7c76f0..e1e30e1d74f0 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
@@ -17,7 +17,9 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder
import android.graphics.Color
import android.graphics.Rect
+import android.util.Log
import android.view.View
+import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.annotation.ColorInt
import androidx.collection.ArrayMap
@@ -220,7 +222,7 @@ object NotificationIconContainerViewBinder {
notifyBindingFailures: (Collection<String>) -> Unit,
viewStore: IconViewStore,
bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit = { _, _ -> },
- ): Unit = coroutineScope {
+ ) {
val iconSizeFlow: Flow<Int> =
configuration.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size_sp,
@@ -235,6 +237,21 @@ object NotificationIconContainerViewBinder {
->
FrameLayout.LayoutParams(iconSize + 2 * iconHPadding, statusBarHeight)
}
+ try {
+ bindIcons(view, layoutParams, notifyBindingFailures, viewStore, bindIcon)
+ } finally {
+ // Detach everything so that child SBIVs don't hold onto a reference to the container.
+ view.detachAllIcons()
+ }
+ }
+
+ private suspend fun Flow<NotificationIconsViewData>.bindIcons(
+ view: NotificationIconContainer,
+ layoutParams: Flow<FrameLayout.LayoutParams>,
+ notifyBindingFailures: (Collection<String>) -> Unit,
+ viewStore: IconViewStore,
+ bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit,
+ ): Unit = coroutineScope {
val failedBindings = mutableSetOf<String>()
val boundViewsByNotifKey = ArrayMap<String, Pair<StatusBarIconView, Job>>()
var prevIcons = NotificationIconsViewData()
@@ -266,9 +283,17 @@ object NotificationIconContainerViewBinder {
continue
}
failedBindings.remove(notifKey)
- // The view might still be transiently added if it was just removed and added
- // again
- view.removeTransientView(sbiv)
+ (sbiv.parent as? ViewGroup)?.run {
+ if (this !== view) {
+ Log.wtf(TAG, "StatusBarIconView($notifKey) has an unexpected parent")
+ }
+ // If the container was re-inflated and re-bound, then SBIVs might still be
+ // attached to the prior view.
+ removeView(sbiv)
+ // The view might still be transiently added if it was just removed and
+ // added again.
+ removeTransientView(sbiv)
+ }
view.addView(sbiv, idx)
boundViewsByNotifKey.remove(notifKey)?.second?.cancel()
boundViewsByNotifKey[notifKey] =
@@ -351,7 +376,8 @@ object NotificationIconContainerViewBinder {
fun iconView(key: String): StatusBarIconView?
}
- @ColorInt private val DEFAULT_AOD_ICON_COLOR = Color.WHITE
+ @ColorInt private const val DEFAULT_AOD_ICON_COLOR = Color.WHITE
+ private const val TAG = "NotifIconContainerViewBinder"
}
/** [IconViewStore] for the [com.android.systemui.statusbar.NotificationShelf] */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
index adf6cca1ac65..625fdc1c12f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
@@ -20,6 +20,8 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import android.content.Context
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.SplitShadeStateController
import javax.inject.Inject
@@ -28,6 +30,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
@@ -39,7 +42,9 @@ class SharedNotificationContainerInteractor
constructor(
configurationRepository: ConfigurationRepository,
private val context: Context,
- private val splitShadeStateController: SplitShadeStateController
+ private val splitShadeStateController: SplitShadeStateController,
+ keyguardInteractor: KeyguardInteractor,
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
) {
private val _topPosition = MutableStateFlow(0f)
@@ -75,6 +80,19 @@ constructor(
}
.distinctUntilChanged()
+ /**
+ * The notification shelf can extend over the lock icon area if:
+ * * UDFPS supported. Ambient indication will always appear below
+ * * UDFPS not supported and ambient indication not visible, which will appear above lock icon
+ */
+ val useExtraShelfSpace: Flow<Boolean> =
+ combine(
+ keyguardInteractor.ambientIndicationVisible,
+ deviceEntryUdfpsInteractor.isUdfpsSupported,
+ ) { ambientIndicationVisible, isUdfpsSupported ->
+ isUdfpsSupported || !ambientIndicationVisible
+ }
+
val isSplitShadeEnabled: Flow<Boolean> =
configurationBasedDimensions
.map { dimens: ConfigurationBasedDimensions -> dimens.useSplitShade }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index af56a3f51281..12927b87630e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -101,12 +101,13 @@ object SharedNotificationContainerBinder {
launch {
viewModel
- .getMaxNotifications { space ->
+ .getMaxNotifications { space, extraShelfSpace ->
+ val shelfHeight = controller.getShelfHeight().toFloat()
notificationStackSizeCalculator.computeMaxKeyguardNotifications(
controller.getView(),
space,
- 0f, // Vertical space for shelf is already accounted for
- controller.getShelfHeight().toFloat(),
+ if (extraShelfSpace) shelfHeight else 0f,
+ shelfHeight,
)
}
.collect { controller.setMaxDisplayedNotifications(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 9594bc3bfd86..eff91e55d9a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -229,7 +229,7 @@ constructor(
* When expanding or when the user is interacting with the shade, keep the count stable; do not
* emit a value.
*/
- fun getMaxNotifications(calculateSpace: (Float) -> Int): Flow<Int> {
+ fun getMaxNotifications(calculateSpace: (Float, Boolean) -> Int): Flow<Int> {
val showLimitedNotifications = isOnLockscreenWithoutShade
val showUnlimitedNotifications =
combine(
@@ -245,11 +245,17 @@ constructor(
shadeInteractor.isUserInteracting,
bounds,
interactor.notificationStackChanged.onStart { emit(Unit) },
- ) { showLimitedNotifications, showUnlimitedNotifications, isUserInteracting, bounds, _
- ->
+ interactor.useExtraShelfSpace,
+ ) { flows ->
+ val showLimitedNotifications = flows[0] as Boolean
+ val showUnlimitedNotifications = flows[1] as Boolean
+ val isUserInteracting = flows[2] as Boolean
+ val bounds = flows[3] as NotificationContainerBounds
+ val useExtraShelfSpace = flows[5] as Boolean
+
if (!isUserInteracting) {
if (showLimitedNotifications) {
- emit(calculateSpace(bounds.bottom - bounds.top))
+ emit(calculateSpace(bounds.bottom - bounds.top, useExtraShelfSpace))
} else if (showUnlimitedNotifications) {
emit(-1)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 644c8962b93d..e66d9e8ca531 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -48,6 +48,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
@@ -119,12 +120,13 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements OnHeadsUp
@Main Handler handler,
GlobalSettings globalSettings,
SystemClock systemClock,
+ @Main DelayableExecutor executor,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
ShadeInteractor shadeInteractor) {
- super(context, logger, handler, globalSettings, systemClock, accessibilityManagerWrapper,
- uiEventLogger);
+ super(context, logger, handler, globalSettings, systemClock, executor,
+ accessibilityManagerWrapper, uiEventLogger);
Resources resources = mContext.getResources();
mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
statusBarStateController.addCallback(mStatusBarStateListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 00e78a49ba19..0dabafbdecb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -400,6 +400,21 @@ public class NotificationIconContainer extends ViewGroup {
}
}
+ /**
+ * Removes all child {@link StatusBarIconView} instances from this container, immediately and
+ * without animation. This should be called when tearing down this container so that external
+ * icon views are not holding onto a reference thru {@link View#getParent()}.
+ */
+ public void detachAllIcons() {
+ boolean animsWereEnabled = mAnimationsEnabled;
+ boolean wasChangingPositions = mChangingViewPositions;
+ mAnimationsEnabled = false;
+ mChangingViewPositions = true;
+ removeAllViews();
+ mChangingViewPositions = wasChangingPositions;
+ mAnimationsEnabled = animsWereEnabled;
+ }
+
public boolean areIconsOverflowing() {
return mIsShowingOverflowDot;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index daadedb06187..4999123247a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -36,6 +36,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
+import android.view.WindowInsetsController;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
import android.window.OnBackInvokedDispatcher;
@@ -859,10 +860,19 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
}
+ private void setRootViewAnimationDisabled(boolean disabled) {
+ ViewGroup windowRootView = mNotificationShadeWindowController.getWindowRootView();
+ if (windowRootView != null) {
+ WindowInsetsController insetsController = windowRootView.getWindowInsetsController();
+ if (insetsController != null) {
+ insetsController.setAnimationsDisabled(disabled);
+ }
+ }
+ }
+
@Override
public void onStartedWakingUp() {
- mNotificationShadeWindowController.getWindowRootView().getWindowInsetsController()
- .setAnimationsDisabled(false);
+ setRootViewAnimationDisabled(false);
NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView();
if (navBarView != null) {
navBarView.forEachView(view ->
@@ -875,8 +885,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public void onStartedGoingToSleep() {
- mNotificationShadeWindowController.getWindowRootView().getWindowInsetsController()
- .setAnimationsDisabled(true);
+ setRootViewAnimationDisabled(true);
NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView();
if (navBarView != null) {
navBarView.forEachView(view ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index 8054b04529c8..e9711284cfca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -38,6 +38,7 @@ import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.util.ListenerSet;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
@@ -87,9 +88,10 @@ public abstract class BaseHeadsUpManager extends AlertingNotificationManager imp
@Main Handler handler,
GlobalSettings globalSettings,
SystemClock systemClock,
+ @Main DelayableExecutor executor,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger) {
- super(logger, handler, systemClock);
+ super(logger, systemClock, executor);
mContext = context;
mAccessibilityMgr = accessibilityManagerWrapper;
mUiEventLogger = uiEventLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
index ef07eed467dc..f6154afec273 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
@@ -66,6 +66,26 @@ class HeadsUpManagerLogger @Inject constructor(
})
}
+ fun logAutoRemoveScheduled(entry: NotificationEntry, delayMillis: Long, reason: String) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ long1 = delayMillis
+ str2 = reason
+ }, {
+ "schedule auto remove of $str1 in $long1 ms reason: $str2"
+ })
+ }
+
+ fun logAutoRemoveRescheduled(entry: NotificationEntry, delayMillis: Long, reason: String) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ long1 = delayMillis
+ str2 = reason
+ }, {
+ "reschedule auto remove of $str1 in $long1 ms reason: $str2"
+ })
+ }
+
fun logAutoRemoveCanceled(entry: NotificationEntry, reason: String?) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 756c440eca89..0c5472f0ecfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -41,6 +41,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
@@ -49,6 +50,7 @@ import dagger.Lazy;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -210,23 +212,33 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
private void notifyKeyguardChanged() {
Trace.beginSection("KeyguardStateController#notifyKeyguardChanged");
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
+ invokeForEachCallback(Callback::onKeyguardShowingChanged);
Trace.endSection();
}
private void notifyKeyguardFaceAuthEnabledChanged() {
+ invokeForEachCallback(Callback::onFaceEnrolledChanged);
+ }
+
+ private void invokeForEachCallback(Consumer<Callback> consumer) {
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(callback -> {
+ ArrayList<Callback> copyOfCallbacks = new ArrayList<>(mCallbacks);
+ for (int i = 0; i < copyOfCallbacks.size(); i++) {
+ Callback callback = copyOfCallbacks.get(i);
+ // Temporary fix for b/315731775, callback is null even though only non-null callbacks
+ // are added to the list by addCallback
if (callback != null) {
- callback.onFaceEnrolledChanged();
+ consumer.accept(callback);
+ } else {
+ mLogger.log("KeyguardStateController callback is null", LogLevel.DEBUG);
}
- });
+ }
}
private void notifyUnlockedChanged() {
Trace.beginSection("KeyguardStateController#notifyUnlockedChanged");
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(Callback::onUnlockedChanged);
+ invokeForEachCallback(Callback::onUnlockedChanged);
Trace.endSection();
}
@@ -242,10 +254,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardFadingAway",
keyguardFadingAway ? 1 : 0);
mKeyguardFadingAway = keyguardFadingAway;
- ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
- for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).onKeyguardFadingAwayChanged();
- }
+ invokeForEachCallback(Callback::onKeyguardFadingAwayChanged);
}
}
@@ -359,7 +368,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardGoingAway",
keyguardGoingAway ? 1 : 0);
mKeyguardGoingAway = keyguardGoingAway;
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardGoingAwayChanged);
+ invokeForEachCallback(Callback::onKeyguardGoingAwayChanged);
}
}
@@ -368,7 +377,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
if (mPrimaryBouncerShowing != showing) {
mPrimaryBouncerShowing = showing;
- new ArrayList<>(mCallbacks).forEach(Callback::onPrimaryBouncerShowingChanged);
+ invokeForEachCallback(Callback::onPrimaryBouncerShowingChanged);
}
}
@@ -392,13 +401,13 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
boolean dismissingFromTouch) {
mDismissAmount = dismissAmount;
mDismissingFromTouch = dismissingFromTouch;
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged);
+ invokeForEachCallback(Callback::onKeyguardDismissAmountChanged);
}
@Override
public void setLaunchTransitionFadingAway(boolean fadingAway) {
mLaunchTransitionFadingAway = fadingAway;
- new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
+ invokeForEachCallback(Callback::onLaunchTransitionFadingAwayChanged);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 886fa70d715d..2b9ad50c1257 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -18,8 +18,8 @@ package com.android.systemui.theme;
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.Flags.themeOverlayControllerWakefulnessDeprecation;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET;
@@ -364,15 +364,23 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- boolean newWorkProfile = Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction());
- boolean isManagedProfile = mUserManager.isManagedProfile(
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
- if (newWorkProfile) {
- if (!mDeviceProvisionedController.isCurrentUserSetup() && isManagedProfile) {
+ boolean newProfile = Intent.ACTION_PROFILE_ADDED.equals(intent.getAction());
+ if (newProfile) {
+ UserHandle newUserHandle = intent.getParcelableExtra(Intent.EXTRA_USER,
+ android.os.UserHandle.class);
+ boolean isManagedProfile =
+ mUserManager.isManagedProfile(newUserHandle.getIdentifier());
+ if (!mDeviceProvisionedController.isUserSetup(newUserHandle.getIdentifier())
+ && isManagedProfile) {
Log.i(TAG, "User setup not finished when " + intent.getAction()
+ " was received. Deferring... Managed profile? " + isManagedProfile);
return;
}
+ if (android.os.Flags.allowPrivateProfile() && isPrivateProfile(newUserHandle)) {
+ mDeferredThemeEvaluation = true;
+ Log.i(TAG, "Deferring theme for private profile till user setup is complete");
+ return;
+ }
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
reevaluateSystemTheme(true /* forceReload */);
} else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
@@ -432,7 +440,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
public void start() {
if (DEBUG) Log.d(TAG, "Start");
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ filter.addAction(Intent.ACTION_PROFILE_ADDED);
filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
UserHandle.ALL);
@@ -608,6 +616,15 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
return new FabricatedOverlay.Builder("com.android.systemui", name, "android").build();
}
+ @VisibleForTesting
+ protected boolean isPrivateProfile(UserHandle userHandle) {
+ Context usercontext = mContext.createContextAsUser(userHandle,0);
+ if (usercontext.getSystemService(UserManager.class).isPrivateProfile()) {
+ return true;
+ }
+ return false;
+ }
+
private void createOverlays(int color) {
boolean nightMode = isNightMode();
mColorScheme = new ColorScheme(color, nightMode, mThemeStyle);
@@ -784,7 +801,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
Set<UserHandle> managedProfiles = new HashSet<>();
for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
- if (userInfo.isManagedProfile()) {
+ if (userInfo.isProfile()) {
managedProfiles.add(userInfo.getUserHandle());
}
}
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 3ed05aac3e10..0fb4b43865aa 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
@@ -2,9 +2,8 @@ package com.android.systemui.user.domain.interactor
import android.annotation.UserIdInt
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.Flags.refactorGetCurrentUser
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -12,12 +11,7 @@ import kotlinx.coroutines.flow.map
/** Encapsulates business logic to interact the selected user */
@SysUISingleton
-class SelectedUserInteractor
-@Inject
-constructor(
- private val repository: UserRepository,
- private val flags: FeatureFlagsClassic,
-) {
+class SelectedUserInteractor @Inject constructor(private val repository: UserRepository) {
/** Flow providing the ID of the currently selected user. */
val selectedUser = repository.selectedUserInfo.map { it.id }.distinctUntilChanged()
@@ -34,7 +28,7 @@ constructor(
@UserIdInt
@JvmOverloads
fun getSelectedUserId(bypassFlag: Boolean = false): Int {
- return if (bypassFlag || flags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ return if (bypassFlag || refactorGetCurrentUser()) {
repository.getSelectedUserInfo().id
} else {
KeyguardUpdateMonitor.getCurrentUser()
diff --git a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
index 5b0943a77979..a89fdda01537 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
@@ -60,6 +60,12 @@ fun IndentingPrintWriter.withIncreasedIndent(runnable: Runnable) {
fun IndentingPrintWriter.println(label: String, value: Any?) =
append(label).append('=').println(value)
+/** Print a section with a header using the given name and an indented body */
+inline fun IndentingPrintWriter.printSection(sectionName: String, block: () -> Unit) {
+ append(sectionName).println(":")
+ withIncreasedIndent(block)
+}
+
@JvmOverloads
inline fun <T> IndentingPrintWriter.printCollection(
label: String,
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Log.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Log.kt
new file mode 100644
index 000000000000..2f6c450e924c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Log.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.kotlin
+
+import android.util.Log
+
+/** Logs message at [Log.DEBUG] level. Won't call the lambda if [DEBUG] is not loggable. */
+inline fun logD(tag: String, messageLambda: () -> String) {
+ if (Log.isLoggable(tag, Log.DEBUG)) {
+ Log.d(tag, messageLambda.invoke())
+ }
+}
+
+/** Logs message at [Log.VERBOSE] level. Won't call the lambda if [VERBOSE] is not loggable. */
+inline fun logV(tag: String, messageLambda: () -> String) {
+ if (Log.isLoggable(tag, Log.VERBOSE)) {
+ Log.v(tag, messageLambda.invoke())
+ }
+}
+
+/** Logs message at [Log.INFO] level. Won't call the lambda if [INFO] is not loggable. */
+inline fun logI(tag: String, messageLambda: () -> String) {
+ if (Log.isLoggable(tag, Log.INFO)) {
+ Log.i(tag, messageLambda.invoke())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index ea20d29556dc..91219f02818c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -47,12 +47,14 @@ import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorI
import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.events.ANIMATING_OUT
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -101,6 +103,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
lateinit var interactionJankMonitor: InteractionJankMonitor
@Mock
lateinit var vibrator: VibratorHelper
+ @Mock
+ lateinit var udfpsUtils: UdfpsUtils
+ @Mock
+ lateinit var authController: AuthController
+ @Mock
+ lateinit var selectedUserInteractor: SelectedUserInteractor
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
@@ -123,6 +131,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
private lateinit var displayRepository: FakeDisplayRepository
private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
@@ -140,6 +149,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
displayStateRepository,
displayRepository,
)
+ udfpsOverlayInteractor =
+ UdfpsOverlayInteractor(
+ authController,
+ selectedUserInteractor,
+ testScope.backgroundScope,
+ )
}
@After
@@ -532,6 +547,8 @@ open class AuthContainerViewTest : SysuiTestCase() {
displayStateInteractor,
promptSelectorInteractor,
context,
+ udfpsOverlayInteractor,
+ udfpsUtils
),
{ credentialViewModel },
Handler(TestableLooper.get(this).looper),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 8e54eb7334dd..4c510ee0b8a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -27,6 +27,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.logging.KeyguardLogger
+import com.android.systemui.Flags.FLAG_LIGHT_REVEAL_MIGRATION
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FeatureFlags
@@ -40,6 +41,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.mockito.any
+import javax.inject.Provider
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -51,14 +53,14 @@ import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import javax.inject.Provider
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -246,6 +248,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Test
@RunWithLooper(setAsMainLooper = true)
fun testAnimatorRunWhenWakeAndUnlock_fingerprint() {
+ mSetFlagsRule.disableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
val fpsLocation = Point(5, 5)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
@@ -266,6 +269,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Test
@RunWithLooper(setAsMainLooper = true)
fun testAnimatorRunWhenWakeAndUnlock_faceUdfpsFingerDown() {
+ mSetFlagsRule.disableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
val faceLocation = Point(5, 5)
`when`(authController.faceSensorLocation).thenReturn(faceLocation)
controller.onViewAttached()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
new file mode 100644
index 000000000000..27d93eb31922
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.biometrics.data.repository
+
+import android.hardware.biometrics.AuthenticationStateListener
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+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.Rule
+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.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BiometricStatusRepositoryTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var biometricManager: BiometricManager
+
+ private lateinit var underTest: BiometricStatusRepository
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setUp() {
+ underTest = BiometricStatusRepositoryImpl(testScope.backgroundScope, biometricManager)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenBiometricPromptAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_BP)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.BiometricPromptAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenDeviceEntryAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_KEYGUARD)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.DeviceEntryAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenOtherAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_OTHER)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.OtherAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenSettingsAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_SETTINGS)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER))
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenEnrollmentAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_ENROLL_FIND_SENSOR)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ )
+
+ listener.onAuthenticationStarted(REASON_ENROLL_ENROLLING)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenAuthenticationStopped() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ listener.onAuthenticationStarted(REASON_AUTH_BP)
+ listener.onAuthenticationStopped()
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+}
+
+private fun BiometricManager.captureListener() =
+ withArgCaptor<AuthenticationStateListener> {
+ verify(this@captureListener).registerAuthenticationStateListener(capture())
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
new file mode 100644
index 000000000000..6978923879b4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.biometrics.domain.interactor
+
+import android.app.ActivityManager
+import android.app.ActivityTaskManager
+import android.content.ComponentName
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.google.common.truth.Truth.assertThat
+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.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BiometricStatusInteractorImplTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+
+ private lateinit var biometricStatusRepository: FakeBiometricStatusRepository
+ private lateinit var underTest: BiometricStatusInteractorImpl
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setup() {
+ biometricStatusRepository = FakeBiometricStatusRepository()
+ underTest = BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenBiometricPromptAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(AuthenticationReason.BiometricPromptAuthentication)
+ }
+
+ @Test
+ fun doesNotUpdateSfpsAuthenticationReason_whenDeviceEntryAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.DeviceEntryAuthentication
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenOtherAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.OtherAuthentication
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.OtherAuthentication)
+ }
+
+ @Test
+ fun doesNotUpdateSfpsAuthenticationReason_whenOtherSettingsAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ `when`(activityTaskManager.getTasks(Mockito.anyInt()))
+ .thenReturn(listOf(fpSettingsTask()))
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER)
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenEnrollmentAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_FIND_SENSOR)
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ )
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenAuthenticationStopped() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+}
+
+private fun fpSettingsTask() = settingsTask(".biometrics.fingerprint.FingerprintSettings")
+
+private fun settingsTask(cls: String) =
+ ActivityManager.RunningTaskInfo().apply {
+ topActivity = ComponentName.createRelative("com.android.settings", cls)
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
index 22e3e7fedda0..74c43131b955 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics.shared.model
+import android.hardware.fingerprint.FingerprintSensorProperties
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.faceSensorPropertiesInternal
@@ -35,6 +36,46 @@ class BiometricModalitiesTest : SysuiTestCase() {
}
@Test
+ fun hasUdfps() {
+ with(
+ BiometricModalities(
+ fingerprintProperties = fingerprintSensorPropertiesInternal(
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ ).first(),
+ )
+ ) {
+ assertThat(isEmpty).isFalse()
+ assertThat(hasUdfps).isTrue()
+ assertThat(hasSfps).isFalse()
+ assertThat(hasFace).isFalse()
+ assertThat(hasFaceOnly).isFalse()
+ assertThat(hasFingerprint).isTrue()
+ assertThat(hasFingerprintOnly).isTrue()
+ assertThat(hasFaceAndFingerprint).isFalse()
+ }
+ }
+
+ @Test
+ fun hasSfps() {
+ with(
+ BiometricModalities(
+ fingerprintProperties = fingerprintSensorPropertiesInternal(
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ ).first(),
+ )
+ ) {
+ assertThat(isEmpty).isFalse()
+ assertThat(hasUdfps).isFalse()
+ assertThat(hasSfps).isTrue()
+ assertThat(hasFace).isFalse()
+ assertThat(hasFaceOnly).isFalse()
+ assertThat(hasFingerprint).isTrue()
+ assertThat(hasFingerprintOnly).isTrue()
+ assertThat(hasFaceAndFingerprint).isFalse()
+ }
+ }
+
+ @Test
fun fingerprintOnly() {
with(
BiometricModalities(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
new file mode 100644
index 000000000000..b4ae00ddd608
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
@@ -0,0 +1,484 @@
+/*
+ * 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.biometrics.ui.binder
+
+import android.animation.Animator
+import android.app.ActivityTaskManager
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManagerGlobal
+import android.os.Handler
+import android.testing.TestableLooper
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.test.filters.SmallTest
+import com.airbnb.lottie.LottieAnimationView
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
+import com.android.systemui.biometrics.FpsUnlockTracker
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.dump.logcatLogBuffer
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.log.SideFpsLogger
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+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.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class SideFpsOverlayViewBinderTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+ @Mock private lateinit var displayManager: DisplayManager
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock
+ private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
+ @Mock private lateinit var fpsUnlockTracker: FpsUnlockTracker
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var layoutInflater: LayoutInflater
+ @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var sideFpsView: View
+ @Mock private lateinit var windowManager: WindowManager
+
+ private val contextDisplayInfo = DisplayInfo()
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+ private val biometricStatusRepository = FakeBiometricStatusRepository()
+ private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ private val displayRepository = FakeDisplayRepository()
+ private val displayStateRepository = FakeDisplayStateRepository()
+ private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
+ private lateinit var underTest: SideFpsOverlayViewBinder
+
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private lateinit var biometricStatusInteractor: BiometricStatusInteractor
+ private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractorImpl
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
+
+ private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+
+ private lateinit var viewModel: SideFpsOverlayViewModel
+
+ private var displayWidth: Int = 0
+ private var displayHeight: Int = 0
+ private var boundsWidth: Int = 0
+ private var boundsHeight: Int = 0
+
+ private lateinit var deviceConfig: DeviceConfig
+ private lateinit var sensorLocation: SensorLocationInternal
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ enum class DeviceConfig {
+ X_ALIGNED,
+ Y_ALIGNED,
+ }
+
+ @Before
+ fun setup() {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+
+ allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread
+
+ mContext = spy(mContext)
+
+ val resources = mContext.resources
+ whenever(mContext.display)
+ .thenReturn(
+ Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
+ )
+
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ fingerprintPropertyRepository,
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+
+ biometricStatusInteractor =
+ BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
+ )
+ displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
+
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ selectedUserInteractor,
+ faceAuthInteractor
+ )
+
+ deviceEntrySideFpsOverlayInteractor =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
+ .thenReturn(MutableStateFlow(false))
+
+ sfpsSensorInteractor =
+ SideFpsSensorInteractor(
+ mContext,
+ fingerprintPropertyRepository,
+ windowManager,
+ displayStateInteractor,
+ Optional.of(fingerprintInteractiveToAuthProvider),
+ SideFpsLogger(logcatLogBuffer("SfpsLogger"))
+ )
+
+ sideFpsProgressBarViewModel =
+ SideFpsProgressBarViewModel(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ sfpsSensorInteractor,
+ displayStateInteractor,
+ testScope.backgroundScope,
+ )
+
+ viewModel =
+ SideFpsOverlayViewModel(
+ mContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel
+ )
+
+ underTest =
+ SideFpsOverlayViewBinder(
+ testScope.backgroundScope,
+ mContext,
+ biometricStatusInteractor,
+ displayStateInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ fpsUnlockTracker,
+ layoutInflater,
+ sideFpsProgressBarViewModel,
+ sfpsSensorInteractor,
+ windowManager
+ )
+
+ context.addMockSystemService(DisplayManager::class.java, displayManager)
+ context.addMockSystemService(WindowManager::class.java, windowManager)
+
+ `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView)
+ `when`(sideFpsView.requireViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
+ .thenReturn(mock(LottieAnimationView::class.java))
+ with(mock(ViewPropertyAnimator::class.java)) {
+ `when`(sideFpsView.animate()).thenReturn(this)
+ `when`(alpha(Mockito.anyFloat())).thenReturn(this)
+ `when`(setStartDelay(Mockito.anyLong())).thenReturn(this)
+ `when`(setDuration(Mockito.anyLong())).thenReturn(this)
+ `when`(setListener(any())).thenAnswer {
+ (it.arguments[0] as Animator.AnimatorListener).onAnimationEnd(
+ mock(Animator::class.java)
+ )
+ this
+ }
+ }
+ }
+
+ @Test
+ fun verifyIndicatorNotAdded_whenInRearDisplayMode() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = true
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager, never()).addView(any(), any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShowAndHide_onPrimaryBouncerShowAndHide() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ // Show primary bouncer
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // Hide primary bouncer
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShowAndHide_onAlternateBouncerShowAndHide() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ // Show alternate bouncer
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // Hide alternate bouncer
+ bouncerRepository.setAlternateVisible(false)
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShownAndHidden_onSystemServerAuthenticationStartedAndStopped() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ // System server authentication started
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // System server authentication stopped
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+
+ private suspend fun TestScope.setupTestConfiguration(
+ deviceConfig: DeviceConfig,
+ rotation: DisplayRotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode: Boolean,
+ ) {
+ this@SideFpsOverlayViewBinderTest.deviceConfig = deviceConfig
+
+ when (deviceConfig) {
+ DeviceConfig.X_ALIGNED -> {
+ displayWidth = 3000
+ displayHeight = 1500
+ boundsWidth = 200
+ boundsHeight = 100
+ sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2)
+ }
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ boundsWidth = 100
+ boundsHeight = 200
+ sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2)
+ }
+ }
+
+ whenever(windowManager.maximumWindowMetrics)
+ .thenReturn(
+ WindowMetrics(
+ Rect(0, 0, displayWidth, displayHeight),
+ mock(WindowInsets::class.java),
+ )
+ )
+
+ contextDisplayInfo.uniqueId = DISPLAY_ID
+
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.POWER_BUTTON,
+ sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
+ )
+
+ displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+ displayStateRepository.setCurrentRotation(rotation)
+ displayRepository.emitDisplayChangeEvent(0)
+ underTest.start()
+ runCurrent()
+ }
+
+ companion object {
+ private const val DISPLAY_ID = "displayId"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index d06cbbb5e433..7475235cfeae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.ui.viewmodel
import android.content.res.Configuration
+import android.graphics.Point
import android.hardware.biometrics.PromptInfo
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.fingerprint.FingerprintSensorProperties
@@ -25,7 +26,10 @@ import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.Flags.FLAG_BP_TALKBACK
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
@@ -33,6 +37,7 @@ import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.extractAuthenticatorTypes
import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
@@ -45,8 +50,10 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.res.R
-import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -77,7 +84,9 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
@Mock private lateinit var lockPatternUtils: LockPatternUtils
- @Mock private lateinit var vibrator: VibratorHelper
+ @Mock private lateinit var authController: AuthController
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var udfpsUtils: UdfpsUtils
private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val testScope = TestScope()
@@ -87,6 +96,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
private lateinit var displayStateRepository: FakeDisplayStateRepository
private lateinit var displayRepository: FakeDisplayRepository
private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
private lateinit var selector: PromptSelectorInteractor
private lateinit var viewModel: PromptViewModel
@@ -116,11 +126,24 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
displayStateRepository,
displayRepository,
)
+ udfpsOverlayInteractor =
+ UdfpsOverlayInteractor(
+ authController,
+ selectedUserInteractor,
+ testScope.backgroundScope
+ )
selector =
PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
selector.resetPrompt()
- viewModel = PromptViewModel(displayStateInteractor, selector, mContext)
+ viewModel =
+ PromptViewModel(
+ displayStateInteractor,
+ selector,
+ mContext,
+ udfpsOverlayInteractor,
+ udfpsUtils
+ )
iconViewModel = viewModel.iconViewModel
}
@@ -1153,6 +1176,29 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(size).isEqualTo(PromptSize.LARGE)
}
+ @Test
+ fun hint_for_talkback_guidance() = runGenericTest {
+ mSetFlagsRule.enableFlags(FLAG_BP_TALKBACK)
+ val hint by collectLastValue(viewModel.accessibilityHint)
+
+ // Touches should fall outside of sensor area
+ whenever(udfpsUtils.getTouchInNativeCoordinates(any(), any(), any()))
+ .thenReturn(Point(0, 0))
+ whenever(udfpsUtils.onTouchOutsideOfSensorArea(any(), any(), any(), any(), any()))
+ .thenReturn("Direction")
+
+ viewModel.onAnnounceAccessibilityHint(
+ obtainMotionEvent(MotionEvent.ACTION_HOVER_ENTER),
+ true
+ )
+
+ if (testCase.modalities.hasUdfps) {
+ assertThat(hint?.isNotBlank()).isTrue()
+ } else {
+ assertThat(hint.isNullOrBlank()).isTrue()
+ }
+ }
+
/** Asserts that the selected buttons are visible now. */
private suspend fun TestScope.assertButtonsVisible(
tryAgain: Boolean = false,
@@ -1220,14 +1266,19 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
authenticatedModality = BiometricModality.Face,
),
TestCase(
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ )
+ .first(),
authenticatedModality = BiometricModality.Fingerprint,
),
TestCase(
fingerprint =
fingerprintSensorPropertiesInternal(
strong = true,
- sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
)
.first(),
authenticatedModality = BiometricModality.Fingerprint,
@@ -1264,19 +1315,29 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
- authenticatedModality = BiometricModality.Fingerprint,
+ authenticatedModality = BiometricModality.Face,
+ confirmationRequested = true,
),
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
- authenticatedModality = BiometricModality.Face,
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ )
+ .first(),
+ authenticatedModality = BiometricModality.Fingerprint,
confirmationRequested = true,
),
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ )
+ .first(),
authenticatedModality = BiometricModality.Fingerprint,
- confirmationRequested = true,
),
)
}
@@ -1309,6 +1370,9 @@ internal data class TestCase(
else -> false
}
+ val modalities: BiometricModalities
+ get() = BiometricModalities(fingerprint, face)
+
val authenticatedByFingerprint: Boolean
get() = authenticatedModality == BiometricModality.Fingerprint
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
new file mode 100644
index 000000000000..2267bdcafad8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
@@ -0,0 +1,576 @@
+/*
+ * 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.biometrics.ui.viewmodel
+
+import android.app.ActivityTaskManager
+import android.content.res.Configuration.UI_MODE_NIGHT_NO
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
+import android.graphics.Color
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.display.DisplayManagerGlobal
+import android.os.Handler
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.test.filters.SmallTest
+import com.airbnb.lottie.model.KeyPath
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.settingslib.Utils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.dump.logcatLogBuffer
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.log.SideFpsLogger
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+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.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class SideFpsOverlayViewModelTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock
+ private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var windowManager: WindowManager
+
+ private val contextDisplayInfo = DisplayInfo()
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+ private val biometricStatusRepository = FakeBiometricStatusRepository()
+ private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ private val displayRepository = FakeDisplayRepository()
+ private val displayStateRepository = FakeDisplayStateRepository()
+ private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
+ private val indicatorColor =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorPrimaryFixed
+ )
+ private val outerRimColor =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorPrimaryFixedDim
+ )
+ private val chevronFill =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
+ )
+ private val color_blue400 =
+ context.getColor(com.android.settingslib.color.R.color.settingslib_color_blue400)
+
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private lateinit var biometricStatusInteractor: BiometricStatusInteractor
+ private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractorImpl
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
+
+ private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+
+ private lateinit var underTest: SideFpsOverlayViewModel
+
+ private var displayWidth: Int = 0
+ private var displayHeight: Int = 0
+ private var boundsWidth: Int = 0
+ private var boundsHeight: Int = 0
+
+ private lateinit var deviceConfig: DeviceConfig
+ private lateinit var sensorLocation: SensorLocationInternal
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ enum class DeviceConfig {
+ X_ALIGNED,
+ Y_ALIGNED,
+ }
+
+ @Before
+ fun setup() {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+
+ mContext = spy(mContext)
+
+ val resources = mContext.resources
+ whenever(mContext.display)
+ .thenReturn(
+ Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
+ )
+
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ fingerprintPropertyRepository,
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+
+ biometricStatusInteractor =
+ BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
+ )
+ displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
+
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ selectedUserInteractor,
+ faceAuthInteractor
+ )
+
+ deviceEntrySideFpsOverlayInteractor =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
+ .thenReturn(MutableStateFlow(false))
+
+ sfpsSensorInteractor =
+ SideFpsSensorInteractor(
+ mContext,
+ fingerprintPropertyRepository,
+ windowManager,
+ displayStateInteractor,
+ Optional.of(fingerprintInteractiveToAuthProvider),
+ SideFpsLogger(logcatLogBuffer("SfpsLogger"))
+ )
+
+ sideFpsProgressBarViewModel =
+ SideFpsProgressBarViewModel(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ sfpsSensorInteractor,
+ displayStateInteractor,
+ testScope.backgroundScope,
+ )
+
+ underTest =
+ SideFpsOverlayViewModel(
+ mContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel,
+ )
+ }
+
+ @Test
+ fun updatesOverlayViewProperties_onDisplayRotationChange_xAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+
+ runCurrent()
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewProperties_onDisplayRotationChange_yAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.Y_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+
+ runCurrent()
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0)
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewParams_onDisplayRotationChange_xAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+
+ underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ runCurrent()
+
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationX)
+ assertThat(overlayViewParams!!.y).isEqualTo(0)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(0)
+ assertThat(overlayViewParams!!.y)
+ .isEqualTo(
+ displayHeight - sensorLocation.sensorLocationX - sensorLocation.sensorRadius * 2
+ )
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x)
+ .isEqualTo(
+ displayWidth - sensorLocation.sensorLocationX - sensorLocation.sensorRadius * 2
+ )
+ assertThat(overlayViewParams!!.y).isEqualTo(displayHeight - boundsHeight)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
+ assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationX)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewParams_onDisplayRotationChange_yAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.Y_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+
+ underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ runCurrent()
+
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
+ assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationY)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationY)
+ assertThat(overlayViewParams!!.y).isEqualTo(0)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(0)
+ assertThat(overlayViewParams!!.y)
+ .isEqualTo(
+ displayHeight - sensorLocation.sensorLocationY - sensorLocation.sensorRadius * 2
+ )
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x)
+ .isEqualTo(
+ displayWidth - sensorLocation.sensorLocationY - sensorLocation.sensorRadius * 2
+ )
+ assertThat(overlayViewParams!!.y).isEqualTo(displayHeight - boundsHeight)
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForDeviceEntry() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), indicatorColor))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), outerRimColor))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".black", "**"), chevronFill))
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inDarkMode() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ setDarkMode(true)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), color_blue400))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), color_blue400))
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inLightMode() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ setDarkMode(false)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".black", "**"), Color.WHITE))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), color_blue400))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), color_blue400))
+ }
+ }
+
+ private fun setDarkMode(inDarkMode: Boolean) {
+ val uiMode =
+ if (inDarkMode) {
+ UI_MODE_NIGHT_YES
+ } else {
+ UI_MODE_NIGHT_NO
+ }
+
+ mContext.resources.configuration.uiMode = uiMode
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+
+ private suspend fun TestScope.setupTestConfiguration(
+ deviceConfig: DeviceConfig,
+ rotation: DisplayRotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode: Boolean,
+ ) {
+ this@SideFpsOverlayViewModelTest.deviceConfig = deviceConfig
+
+ when (deviceConfig) {
+ DeviceConfig.X_ALIGNED -> {
+ displayWidth = 3000
+ displayHeight = 1500
+ boundsWidth = 200
+ boundsHeight = 100
+ sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2)
+ }
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ boundsWidth = 100
+ boundsHeight = 200
+ sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2)
+ }
+ }
+
+ whenever(windowManager.maximumWindowMetrics)
+ .thenReturn(
+ WindowMetrics(
+ Rect(0, 0, displayWidth, displayHeight),
+ mock(WindowInsets::class.java),
+ )
+ )
+
+ contextDisplayInfo.uniqueId = DISPLAY_ID
+
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.POWER_BUTTON,
+ sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
+ )
+
+ displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+
+ displayStateRepository.setCurrentRotation(rotation)
+
+ displayRepository.emitDisplayChangeEvent(0)
+ runCurrent()
+ }
+
+ companion object {
+ private const val DISPLAY_ID = "displayId"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index 37a093e4c23f..dacf23a5a567 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -37,6 +37,7 @@ import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
@@ -342,6 +343,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
assertThat(underTest.willDismissWithAction()).isFalse()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility() {
updateSideFpsVisibilityParameters(
@@ -355,6 +357,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(true)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_notVisible() {
updateSideFpsVisibilityParameters(
@@ -368,6 +371,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_sfpsNotEnabled() {
updateSideFpsVisibilityParameters(
@@ -381,6 +385,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_fpsDetectionNotRunning() {
updateSideFpsVisibilityParameters(
@@ -394,6 +399,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_UnlockingWithFpNotAllowed() {
updateSideFpsVisibilityParameters(
@@ -407,6 +413,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_AnimatingAway() {
updateSideFpsVisibilityParameters(
@@ -492,6 +499,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
isUnlockingWithFpAllowed: Boolean,
isAnimatingAway: Boolean
) {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
whenever(repository.primaryBouncerShow.value).thenReturn(isVisible)
resources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, sfpsEnabled)
whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
index 220718027eee..07c980bb6656 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
@@ -21,14 +21,13 @@ import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.Context;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.view.View;
@@ -48,6 +47,7 @@ import com.android.systemui.controls.management.ControlsListingController;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
@@ -71,9 +71,6 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
private DreamOverlayStateController mDreamOverlayStateController;
@Mock
- private Context mContext;
-
- @Mock
private Resources mResources;
@Mock
@@ -100,6 +97,9 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
@Mock
private UiEventLogger mUiEventLogger;
+ @Mock
+ private ConfigurationController mConfigurationController;
+
@Captor
private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor;
@@ -109,7 +109,8 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mContext.getString(anyInt())).thenReturn("");
+ mContext.ensureTestableResources();
+
when(mControlsComponent.getControlsController()).thenReturn(
Optional.of(mControlsController));
when(mControlsComponent.getControlsListingController()).thenReturn(
@@ -225,6 +226,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
mHomeControlsView,
mActivityStarter,
mContext,
+ mConfigurationController,
mControlsComponent,
mUiEventLogger);
viewController.onViewAttached();
@@ -237,6 +239,24 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase {
verify(mUiEventLogger).log(DreamOverlayUiEvent.DREAM_HOME_CONTROLS_TAPPED);
}
+ @Test
+ public void testUnregistersConfigurationCallback() {
+ final DreamHomeControlsComplication.DreamHomeControlsChipViewController viewController =
+ new DreamHomeControlsComplication.DreamHomeControlsChipViewController(
+ mHomeControlsView,
+ mActivityStarter,
+ mContext,
+ mConfigurationController,
+ mControlsComponent,
+ mUiEventLogger);
+ viewController.onViewAttached();
+ verify(mConfigurationController).addCallback(any());
+ verify(mConfigurationController, never()).removeCallback(any());
+
+ viewController.onViewDetached();
+ verify(mConfigurationController).removeCallback(any());
+ }
+
private void setHaveFavorites(boolean value) {
final List<StructureInfo> favorites = mock(List.class);
when(favorites.isEmpty()).thenReturn(!value);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
index e931384fd61e..65f68f9df3e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt
@@ -22,6 +22,7 @@ import android.provider.Settings
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
+import android.view.View
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -39,6 +40,8 @@ import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.eq
import org.mockito.Mockito.verify
@@ -73,13 +76,20 @@ class ContrastDialogDelegateTest : SysuiTestCase() {
if (Looper.myLooper() == null) Looper.prepare()
mContrastDialogDelegate =
- ContrastDialogDelegate(
- sysuiDialogFactory,
- mainExecutor,
- mockUiModeManager,
- mockUserTracker,
- mockSecureSettings
- )
+ ContrastDialogDelegate(
+ sysuiDialogFactory,
+ mainExecutor,
+ mockUiModeManager,
+ mockUserTracker,
+ mockSecureSettings
+ )
+
+ mContrastDialogDelegate.createDialog()
+ val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+ verify(sysuiDialog).setView(viewCaptor.capture())
+ whenever(sysuiDialog.requireViewById(anyInt()) as View?).then {
+ viewCaptor.value.requireViewById(it.getArgument(0))
+ }
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index ae5f625b1c8d..b38c9ecb6287 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -24,6 +24,7 @@ import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER;
import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -93,6 +94,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.SystemPropertiesHelper;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -190,6 +192,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock ShadeInteractor mShadeInteractor;
private @Mock ShadeWindowLogger mShadeWindowLogger;
private @Mock SelectedUserInteractor mSelectedUserInteractor;
+ private @Mock KeyguardInteractor mKeyguardInteractor;
private @Captor ArgumentCaptor<KeyguardStateController.Callback>
mKeyguardStateControllerCallback;
private @Captor ArgumentCaptor<KeyguardUpdateMonitorCallback>
@@ -264,7 +267,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mSceneContainerFlags);
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
- mFeatureFlags.set(Flags.REFACTOR_GETCURRENTUSER, true);
+ mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER);
DejankUtils.setImmediate(true);
@@ -1131,7 +1134,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mDreamingToLockscreenTransitionViewModel,
mSystemPropertiesHelper,
() -> mock(WindowManagerLockscreenVisibilityManager.class),
- mSelectedUserInteractor);
+ mSelectedUserInteractor,
+ mKeyguardInteractor);
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
new file mode 100644
index 000000000000..70d3f81de35f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
@@ -0,0 +1,238 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import android.os.Handler
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+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.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@SmallTest
+@RunWith(JUnit4::class)
+class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+
+ private lateinit var underTest: DeviceEntrySideFpsOverlayInteractor
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setup() {
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ mSelectedUserInteractor,
+ faceAuthInteractor
+ )
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ FakeFingerprintPropertyRepository(),
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+ underTest =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ FakeDeviceEntryFingerprintAuthRepository(),
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerShowing() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerHidden() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromPrimaryBouncer_whenFpsDetectionNotRunning() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = false,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromPrimaryBouncer_onUnlockingWithFpDisallowed() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = false
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerAnimatingAway() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = true,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onAlternateBouncerRequest() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ bouncerRepository.setAlternateVisible(true)
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+
+ bouncerRepository.setAlternateVisible(false)
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
index 8dea57c2eb34..8e81185d6dcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
@@ -20,8 +20,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -46,11 +44,7 @@ import org.junit.runner.RunWith
class FromPrimaryBouncerTransitionInteractorTest : KeyguardTransitionInteractorTestCase() {
private lateinit var underTest: FromPrimaryBouncerTransitionInteractor
- private val mSelectedUserInteractor =
- SelectedUserInteractor(
- FakeUserRepository(),
- FakeFeatureFlagsClassic().apply { set(Flags.REFACTOR_GETCURRENTUSER, true) }
- )
+ private val mSelectedUserInteractor = SelectedUserInteractor(FakeUserRepository())
// Override the fromPrimaryBouncerTransitionInteractor provider from the superclass so our
// underTest interactor is provided to any classes that need it.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 4ab8e28bc232..6eb95bddaf53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -137,7 +137,6 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
mContext,
testScope.backgroundScope,
dispatcher,
- dispatcher,
faceAuthRepository,
{
PrimaryBouncerInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 687800714e05..459a74c82da4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -184,6 +184,13 @@ class KeyguardRootViewModelTest : SysuiTestCase() {
}
@Test
+ fun translationYInitialValueIsZero() =
+ testScope.runTest {
+ val translationY by collectLastValue(underTest.translationY)
+ assertThat(translationY).isEqualTo(0)
+ }
+
+ @Test
fun translationAndScaleFromBurnInNotDozing() =
testScope.runTest {
val translationX by collectLastValue(underTest.translationX)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 3bfdb84249ac..310e0b8e7ac3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -54,6 +54,7 @@ import com.android.systemui.statusbar.notification.collection.provider.OnReorder
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
@@ -124,6 +125,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Captor lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
private val clock = FakeSystemClock()
+ private lateinit var bgExecutor: FakeExecutor
private lateinit var mediaCarouselController: MediaCarouselController
@Before
@@ -131,6 +133,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
context.resources.configuration.setLocales(LocaleList(Locale.US, Locale.UK))
transitionRepository = FakeKeyguardTransitionRepository()
+ bgExecutor = FakeExecutor(clock)
mediaCarouselController =
MediaCarouselController(
context,
@@ -140,6 +143,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
activityStarter,
clock,
executor,
+ bgExecutor,
mediaDataManager,
configurationController,
falsingManager,
@@ -458,6 +462,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaHostState,
animate = false
)
+ bgExecutor.runAllReady()
verify(logger).logCarouselPosition(LOCATION_QS)
}
@@ -468,6 +473,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaHostState,
animate = false
)
+ bgExecutor.runAllReady()
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QQS)
}
@@ -478,6 +484,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaHostState,
animate = false
)
+ bgExecutor.runAllReady()
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_LOCKSCREEN)
}
@@ -488,6 +495,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaHostState,
animate = false
)
+ bgExecutor.runAllReady()
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_DREAM_OVERLAY)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index b7618d290f53..4d423242893a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -75,6 +75,7 @@ import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
@@ -462,6 +463,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
// region setNoteTaskShortcutEnabled
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_setTrue() {
createNoteTaskController().setNoteTaskShortcutEnabled(value = true, userTracker.userHandle)
@@ -478,6 +480,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_setFalse() {
createNoteTaskController().setNoteTaskShortcutEnabled(value = false, userTracker.userHandle)
@@ -494,6 +497,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_workProfileUser_setTrue() {
whenever(context.createContextAsUser(eq(workUserInfo.userHandle), any()))
.thenReturn(workProfileContext)
@@ -515,6 +519,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun setNoteTaskShortcutEnabled_workProfileUser_setFalse() {
whenever(context.createContextAsUser(eq(workUserInfo.userHandle), any()))
.thenReturn(workProfileContext)
@@ -733,6 +738,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
// region internalUpdateNoteTaskAsUser
@Test
+ @Ignore("b/316332684")
fun updateNoteTaskAsUserInternal_withNotesRole_withShortcuts_shouldUpdateShortcuts() {
createNoteTaskController(isEnabled = true)
.launchUpdateNoteTaskAsUser(userTracker.userHandle)
@@ -766,6 +772,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun updateNoteTaskAsUserInternal_noNotesRole_shouldDisableShortcuts() {
whenever(roleManager.getRoleHoldersAsUser(ROLE_NOTES, userTracker.userHandle))
.thenReturn(emptyList())
@@ -789,6 +796,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
}
@Test
+ @Ignore("b/316332684")
fun updateNoteTaskAsUserInternal_flagDisabled_shouldDisableShortcuts() {
createNoteTaskController(isEnabled = false)
.launchUpdateNoteTaskAsUser(userTracker.userHandle)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index 119ffd28bebe..ebd34de463f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -28,7 +28,6 @@ import android.os.UserManager
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -40,6 +39,7 @@ import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.C
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.res.R
import com.android.systemui.stylus.StylusManager
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -134,12 +134,9 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
// region lockScreenState
@Test
fun lockScreenState_stylusUsed_userUnlocked_isSelected_shouldEmitVisible() = runTest {
- TestConfig()
- .setStylusEverUsed(true)
- .setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(createLockScreenStateVisible())
@@ -148,10 +145,11 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun lockScreenState_stylusUsed_userUnlocked_isSelected_noDefaultNotesAppSet_shouldEmitHidden() =
runTest {
+ val underTest = createUnderTest()
TestConfig()
.setStylusEverUsed(true)
.setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
+ .setConfigSelections(underTest)
whenever(
roleManager.getRoleHoldersAsUser(
eq(RoleManager.ROLE_NOTES),
@@ -160,7 +158,6 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
)
.thenReturn(emptyList())
- val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
@@ -168,12 +165,9 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
- TestConfig()
- .setStylusEverUsed(false)
- .setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
@@ -181,25 +175,22 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
@Test
fun lockScreenState_stylusUsed_userLocked_isSelected_shouldEmitHidden() = runTest {
- TestConfig()
- .setStylusEverUsed(true)
- .setUserUnlocked(false)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
- fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitVisible() = runTest {
+ fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitHidden() = runTest {
TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
@@ -223,13 +214,13 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitVisible() = runTest {
+ fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitHidden() = runTest {
TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(mock())
val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
index 0a8c0ab9817d..e4432f3038bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
@@ -31,18 +31,20 @@ import android.permission.PermissionGroupUsage
import android.permission.PermissionManager
import android.testing.AndroidTestingRunner
import android.view.View
+import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.animation.LaunchableView
import com.android.systemui.appops.AppOpsController
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -56,12 +58,12 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -83,60 +85,48 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
private val TEST_INTENT = Intent("test_intent_action")
}
- @Mock
- private lateinit var dialog: PrivacyDialogV2
- @Mock
- private lateinit var permissionManager: PermissionManager
- @Mock
- private lateinit var packageManager: PackageManager
- @Mock
- private lateinit var privacyItemController: PrivacyItemController
- @Mock
- private lateinit var userTracker: UserTracker
- @Mock
- private lateinit var activityStarter: ActivityStarter
- @Mock
- private lateinit var privacyLogger: PrivacyLogger
- @Mock
- private lateinit var keyguardStateController: KeyguardStateController
- @Mock
- private lateinit var appOpsController: AppOpsController
+ @Mock private lateinit var dialog: PrivacyDialogV2
+ @Mock private lateinit var permissionManager: PermissionManager
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var privacyItemController: PrivacyItemController
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var privacyLogger: PrivacyLogger
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var appOpsController: AppOpsController
@Captor
private lateinit var dialogDismissedCaptor: ArgumentCaptor<PrivacyDialogV2.OnDialogDismissed>
- @Captor
- private lateinit var activityStartedCaptor: ArgumentCaptor<ActivityStarter.Callback>
- @Captor
- private lateinit var intentCaptor: ArgumentCaptor<Intent>
- @Mock
- private lateinit var uiEventLogger: UiEventLogger
- @Mock
- private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+ @Captor private lateinit var activityStartedCaptor: ArgumentCaptor<ActivityStarter.Callback>
+ @Captor private lateinit var intentCaptor: ArgumentCaptor<Intent>
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
private val backgroundExecutor = FakeExecutor(FakeSystemClock())
private val uiExecutor = FakeExecutor(FakeSystemClock())
private lateinit var controller: PrivacyDialogControllerV2
private var nextUid: Int = 0
- private val dialogProvider = object : PrivacyDialogControllerV2.DialogProvider {
- var list: List<PrivacyDialogV2.PrivacyElement>? = null
- var manageApp: ((String, Int, Intent) -> Unit)? = null
- var closeApp: ((String, Int) -> Unit)? = null
- var openPrivacyDashboard: (() -> Unit)? = null
-
- override fun makeDialog(
- context: Context,
- list: List<PrivacyDialogV2.PrivacyElement>,
- manageApp: (String, Int, Intent) -> Unit,
- closeApp: (String, Int) -> Unit,
- openPrivacyDashboard: () -> Unit
- ): PrivacyDialogV2 {
- this.list = list
- this.manageApp = manageApp
- this.closeApp = closeApp
- this.openPrivacyDashboard = openPrivacyDashboard
- return dialog
+ private val dialogProvider =
+ object : PrivacyDialogControllerV2.DialogProvider {
+ var list: List<PrivacyDialogV2.PrivacyElement>? = null
+ var manageApp: ((String, Int, Intent) -> Unit)? = null
+ var closeApp: ((String, Int) -> Unit)? = null
+ var openPrivacyDashboard: (() -> Unit)? = null
+
+ override fun makeDialog(
+ context: Context,
+ list: List<PrivacyDialogV2.PrivacyElement>,
+ manageApp: (String, Int, Intent) -> Unit,
+ closeApp: (String, Int) -> Unit,
+ openPrivacyDashboard: () -> Unit
+ ): PrivacyDialogV2 {
+ this.list = list
+ this.manageApp = manageApp
+ this.closeApp = closeApp
+ this.openPrivacyDashboard = openPrivacyDashboard
+ return dialog
+ }
}
- }
@Before
fun setUp() {
@@ -144,7 +134,8 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
nextUid = 0
setUpDefaultMockResponses()
- controller = PrivacyDialogControllerV2(
+ controller =
+ PrivacyDialogControllerV2(
permissionManager,
packageManager,
privacyItemController,
@@ -158,7 +149,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
uiEventLogger,
dialogLaunchAnimator,
dialogProvider
- )
+ )
}
@After
@@ -197,7 +188,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
verify(packageManager, never()).getApplicationInfoAsUser(anyString(), anyInt(), anyInt())
backgroundExecutor.runAllReady()
verify(packageManager, atLeastOnce())
- .getApplicationInfoAsUser(anyString(), anyInt(), anyInt())
+ .getApplicationInfoAsUser(anyString(), anyInt(), anyInt())
}
@Test
@@ -208,20 +199,25 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
controller.showDialog(context)
exhaustExecutors()
- verify(dialogLaunchAnimator, never()).showFromView(any(), any(), any(), anyBoolean())
+ verify(dialogLaunchAnimator, never()).show(any(), any(), anyBoolean())
verify(dialog).show()
}
@Test
fun testShowDialogShowsDialogWithView() {
- val view = View(context)
+ val parent = LinearLayout(context)
+ val view =
+ object : View(context), LaunchableView {
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {}
+ }
+ parent.addView(view)
val usage = createMockPermGroupUsage()
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context, view)
exhaustExecutors()
- verify(dialogLaunchAnimator).showFromView(dialog, view)
+ verify(dialogLaunchAnimator).show(eq(dialog), any(), anyBoolean())
verify(dialog, never()).show()
}
@@ -276,7 +272,8 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testSingleElementInList() {
- val usage = createMockPermGroupUsage(
+ val usage =
+ createMockPermGroupUsage(
packageName = TEST_PACKAGE_NAME,
uid = generateUidForUser(USER_ID),
permissionGroupName = PERM_CAMERA,
@@ -285,7 +282,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
isPhoneCall = false,
attributionTag = null,
proxyLabel = TEST_PROXY_LABEL
- )
+ )
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
@@ -304,33 +301,38 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
assertThat(list.get(0).isPhoneCall).isFalse()
assertThat(list.get(0).isService).isFalse()
assertThat(list.get(0).permGroupName).isEqualTo(PERM_CAMERA)
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
}
}
private fun isIntentEqual(actual: Intent, expected: Intent): Boolean {
return actual.action == expected.action &&
- actual.getStringExtra(Intent.EXTRA_PACKAGE_NAME) ==
+ actual.getStringExtra(Intent.EXTRA_PACKAGE_NAME) ==
expected.getStringExtra(Intent.EXTRA_PACKAGE_NAME) &&
- actual.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle ==
+ actual.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle ==
expected.getParcelableExtra(Intent.EXTRA_USER) as? UserHandle
}
@Test
fun testTwoElementsDifferentType_sorted() {
- val usage_camera = createMockPermGroupUsage(
+ val usage_camera =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_camera",
permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
+ )
+ val usage_microphone =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_microphone",
permissionGroupName = PERM_MICROPHONE
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_microphone, usage_camera)
- )
+ )
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_microphone, usage_camera))
controller.showDialog(context)
exhaustExecutors()
@@ -343,17 +345,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testTwoElementsSameType_oneActive() {
- val usage_active = createMockPermGroupUsage(
- packageName = "${TEST_PACKAGE_NAME}_active",
- isActive = true
- )
- val usage_recent = createMockPermGroupUsage(
- packageName = "${TEST_PACKAGE_NAME}_recent",
- isActive = false
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_recent, usage_active)
- )
+ val usage_active =
+ createMockPermGroupUsage(packageName = "${TEST_PACKAGE_NAME}_active", isActive = true)
+ val usage_recent =
+ createMockPermGroupUsage(packageName = "${TEST_PACKAGE_NAME}_recent", isActive = false)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_recent, usage_active))
controller.showDialog(context)
exhaustExecutors()
@@ -364,19 +361,20 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testTwoElementsSameType_twoActive() {
- val usage_active = createMockPermGroupUsage(
+ val usage_active =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_active",
isActive = true,
lastAccessTimeMillis = 0L
- )
- val usage_active_moreRecent = createMockPermGroupUsage(
+ )
+ val usage_active_moreRecent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_active_recent",
isActive = true,
lastAccessTimeMillis = 1L
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_active, usage_active_moreRecent)
- )
+ )
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_active, usage_active_moreRecent))
controller.showDialog(context)
exhaustExecutors()
assertThat(dialogProvider.list).hasSize(2)
@@ -386,24 +384,26 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testManyElementsSameType_bothRecent() {
- val usage_recent = createMockPermGroupUsage(
+ val usage_recent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_recent",
isActive = false,
lastAccessTimeMillis = 0L
- )
- val usage_moreRecent = createMockPermGroupUsage(
+ )
+ val usage_moreRecent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_moreRecent",
isActive = false,
lastAccessTimeMillis = 1L
- )
- val usage_mostRecent = createMockPermGroupUsage(
+ )
+ val usage_mostRecent =
+ createMockPermGroupUsage(
packageName = "${TEST_PACKAGE_NAME}_mostRecent",
isActive = false,
lastAccessTimeMillis = 2L
- )
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_recent, usage_mostRecent, usage_moreRecent)
- )
+ )
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_recent, usage_mostRecent, usage_moreRecent))
controller.showDialog(context)
exhaustExecutors()
@@ -414,19 +414,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testMicAndCameraDisabled() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.micCameraAvailable).thenReturn(false)
controller.showDialog(context)
@@ -438,45 +431,29 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testLocationDisabled() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.locationAvailable).thenReturn(false)
controller.showDialog(context)
exhaustExecutors()
assertThat(dialogProvider.list).hasSize(2)
- dialogProvider.list?.forEach {
- assertThat(it.type).isNotEqualTo(PrivacyType.TYPE_LOCATION)
- }
+ dialogProvider.list?.forEach { assertThat(it.type).isNotEqualTo(PrivacyType.TYPE_LOCATION) }
}
@Test
fun testAllIndicatorsAvailable() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.micCameraAvailable).thenReturn(true)
`when`(privacyItemController.locationAvailable).thenReturn(true)
@@ -488,19 +465,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testNoIndicatorsAvailable() {
- val usage_camera = createMockPermGroupUsage(
- permissionGroupName = PERM_CAMERA
- )
- val usage_microphone = createMockPermGroupUsage(
- permissionGroupName = PERM_MICROPHONE
- )
- val usage_location = createMockPermGroupUsage(
- permissionGroupName = PERM_LOCATION
- )
-
- `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(
- listOf(usage_camera, usage_location, usage_microphone)
- )
+ val usage_camera = createMockPermGroupUsage(permissionGroupName = PERM_CAMERA)
+ val usage_microphone = createMockPermGroupUsage(permissionGroupName = PERM_MICROPHONE)
+ val usage_location = createMockPermGroupUsage(permissionGroupName = PERM_LOCATION)
+
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
+ .thenReturn(listOf(usage_camera, usage_location, usage_microphone))
`when`(privacyItemController.micCameraAvailable).thenReturn(false)
`when`(privacyItemController.locationAvailable).thenReturn(false)
@@ -512,11 +482,9 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
@Test
fun testNotCurrentUser() {
- val usage_other = createMockPermGroupUsage(
- uid = generateUidForUser(ENT_USER_ID + 1)
- )
+ val usage_other = createMockPermGroupUsage(uid = generateUidForUser(ENT_USER_ID + 1))
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean()))
- .thenReturn(listOf(usage_other))
+ .thenReturn(listOf(usage_other))
controller.showDialog(context)
exhaustExecutors()
@@ -559,9 +527,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
// Calls happen in
val usage = createMockPermGroupUsage(uid = SYSTEM_UID, isPhoneCall = true)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(userTracker.userProfiles).thenReturn(listOf(
- UserInfo(ENT_USER_ID, "", 0)
- ))
+ `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(ENT_USER_ID, "", 0)))
controller.showDialog(context)
exhaustExecutors()
@@ -577,8 +543,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.manageApp?.invoke(TEST_PACKAGE_NAME, USER_ID, TEST_INTENT)
- verify(uiEventLogger).log(PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS,
- USER_ID, TEST_PACKAGE_NAME)
+ verify(uiEventLogger)
+ .log(
+ PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS,
+ USER_ID,
+ TEST_PACKAGE_NAME
+ )
}
@Test
@@ -589,8 +559,12 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.closeApp?.invoke(TEST_PACKAGE_NAME, USER_ID)
- verify(uiEventLogger).log(PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_CLOSE_APP,
- USER_ID, TEST_PACKAGE_NAME)
+ verify(uiEventLogger)
+ .log(
+ PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_CLOSE_APP,
+ USER_ID,
+ TEST_PACKAGE_NAME
+ )
}
@Test
@@ -629,9 +603,13 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@@ -648,45 +626,58 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(
- TEST_PACKAGE_NAME, ENT_USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(
+ TEST_PACKAGE_NAME,
+ ENT_USER_ID
+ )
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@Test
fun testDefaultIntentOnInvalidAttributionTag() {
- val usage = createMockPermGroupUsage(
+ val usage =
+ createMockPermGroupUsage(
attributionTag = "INVALID_ATTRIBUTION_TAG",
proxyLabel = TEST_PROXY_LABEL
- )
+ )
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@Test
fun testServiceIntentOnCorrectSubAttribution() {
- val usage = createMockPermGroupUsage(
+ val usage =
+ createMockPermGroupUsage(
attributionTag = TEST_ATTRIBUTION_TAG,
attributionLabel = "TEST_LABEL"
- )
+ )
val activityInfo = createMockActivityInfo()
val resolveInfo = createMockResolveInfo(activityInfo)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
- .thenAnswer { resolveInfo }
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenAnswer {
+ resolveInfo
+ }
controller.showDialog(context)
exhaustExecutors()
@@ -694,57 +685,61 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
val navigationIntent = list.get(0).navigationIntent!!
assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE)
assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME))
- .isEqualTo(PERM_CAMERA)
+ .isEqualTo(PERM_CAMERA)
assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS))
- .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
+ .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false))
- .isTrue()
+ .isTrue()
assertThat(list.get(0).isService).isTrue()
}
}
@Test
fun testDefaultIntentOnMissingAttributionLabel() {
- val usage = createMockPermGroupUsage(
- attributionTag = TEST_ATTRIBUTION_TAG
- )
+ val usage = createMockPermGroupUsage(attributionTag = TEST_ATTRIBUTION_TAG)
val activityInfo = createMockActivityInfo()
val resolveInfo = createMockResolveInfo(activityInfo)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
- .thenAnswer { resolveInfo }
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenAnswer {
+ resolveInfo
+ }
controller.showDialog(context)
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@Test
fun testDefaultIntentOnIncorrectPermission() {
- val usage = createMockPermGroupUsage(
- attributionTag = TEST_ATTRIBUTION_TAG
- )
+ val usage = createMockPermGroupUsage(attributionTag = TEST_ATTRIBUTION_TAG)
- val activityInfo = createMockActivityInfo(
- permission = "INCORRECT_PERMISSION"
- )
+ val activityInfo = createMockActivityInfo(permission = "INCORRECT_PERMISSION")
val resolveInfo = createMockResolveInfo(activityInfo)
`when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
- `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
- .thenAnswer { resolveInfo }
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenAnswer {
+ resolveInfo
+ }
controller.showDialog(context)
exhaustExecutors()
dialogProvider.list?.let { list ->
- assertThat(isIntentEqual(list.get(0).navigationIntent!!,
- controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
- .isTrue()
+ assertThat(
+ isIntentEqual(
+ list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)
+ )
+ )
+ .isTrue()
assertThat(list.get(0).isService).isFalse()
}
}
@@ -758,15 +753,18 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
`when`(appOpsController.isMicMuted).thenReturn(false)
`when`(packageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenAnswer { FakeApplicationInfo(it.getArgument(0)) }
+ .thenAnswer { FakeApplicationInfo(it.getArgument(0)) }
`when`(privacyItemController.locationAvailable).thenReturn(true)
`when`(privacyItemController.micCameraAvailable).thenReturn(true)
- `when`(userTracker.userProfiles).thenReturn(listOf(
- UserInfo(USER_ID, "", 0),
- UserInfo(ENT_USER_ID, "", UserInfo.FLAG_MANAGED_PROFILE)
- ))
+ `when`(userTracker.userProfiles)
+ .thenReturn(
+ listOf(
+ UserInfo(USER_ID, "", 0),
+ UserInfo(ENT_USER_ID, "", UserInfo.FLAG_MANAGED_PROFILE)
+ )
+ )
`when`(keyguardStateController.isUnlocked).thenReturn(true)
}
@@ -781,9 +779,7 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
return user * UserHandle.PER_USER_RANGE + nextUid++
}
- private fun createMockResolveInfo(
- activityInfo: ActivityInfo? = null
- ): ResolveInfo {
+ private fun createMockResolveInfo(activityInfo: ActivityInfo? = null): ResolveInfo {
val resolveInfo = mock(ResolveInfo::class.java)
resolveInfo.activityInfo = activityInfo
return resolveInfo
@@ -822,4 +818,4 @@ class PrivacyDialogControllerV2Test : SysuiTestCase() {
`when`(usage.proxyLabel).thenReturn(proxyLabel)
return usage
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index b825c0840e01..018fa9e2bc86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -391,7 +391,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
}
@Test
- public void setTiles_differentTiles_allTilesRemovedAndNewTilesAdded() {
+ public void setTiles_differentTiles_extraTileRemoved() {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
mController.setTiles();
@@ -400,8 +400,8 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile));
mController.setTiles();
- verify(mQSPanel, times(2)).removeTile(any());
- verify(mQSPanel).addTile(any());
+ verify(mQSPanel, times(1)).removeTile(any());
+ verify(mQSPanel, never()).addTile(any());
}
@Test
@@ -418,7 +418,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
}
@Test
- public void setTiles_sameTilesDifferentOrder_removesAndReadds() {
+ public void setTiles_sameTilesDifferentOrder_removesAndReads() {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
mController.setTiles();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
index d8199c527cac..9b61447c8de7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
@@ -23,6 +23,7 @@ import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -30,12 +31,20 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.res.R
+import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isA
import org.mockito.Mock
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
/**
@@ -53,15 +62,23 @@ class RecordIssueTileTest : SysuiTestCase() {
@Mock private lateinit var statusBarStateController: StatusBarStateController
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var qsLogger: QSLogger
-
+ @Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var dialogLauncherAnimator: DialogLaunchAnimator
+ @Mock private lateinit var dialogFactory: SystemUIDialog.Factory
+ @Mock private lateinit var dialog: SystemUIDialog
+ @Mock private lateinit var userContextProvider: UserContextProvider
+
+ private lateinit var testableLooper: TestableLooper
private lateinit var tile: RecordIssueTile
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(host.context).thenReturn(mContext)
+ whenever(dialogFactory.create(any())).thenReturn(dialog)
- val testableLooper = TestableLooper.get(this)
+ testableLooper = TestableLooper.get(this)
tile =
RecordIssueTile(
host,
@@ -72,7 +89,12 @@ class RecordIssueTileTest : SysuiTestCase() {
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
+ keyguardDismissUtil,
+ keyguardStateController,
+ dialogLauncherAnimator,
+ dialogFactory,
+ userContextProvider,
)
}
@@ -119,4 +141,18 @@ class RecordIssueTileTest : SysuiTestCase() {
assertThat(testState.state).isEqualTo(Tile.STATE_ACTIVE)
}
+
+ @Test
+ fun showPrompt_shouldUseKeyguardDismissUtil_ToShowDialog() {
+ tile.isRecording = false
+ tile.handleClick(null)
+ testableLooper.processAllMessages()
+
+ verify(keyguardDismissUtil)
+ .executeWhenUnlocked(
+ isA(ActivityStarter.OnDismissAction::class.java),
+ eq(false),
+ eq(true)
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 6dc7a064af15..b24b8773d600 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -63,13 +63,13 @@ import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.wifi.WifiUtils;
import com.android.settingslib.wifi.dpp.WifiDppIntentHelper;
-import com.android.systemui.res.R;
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.Flags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.LocationController;
@@ -738,6 +738,44 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
+ public void onWifiScan_isWifiEnabledFalse_callbackOnWifiScanFalse() {
+ reset(mInternetDialogCallback);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
+
+ mInternetDialogController.onWifiScan(true);
+
+ verify(mInternetDialogCallback).onWifiScan(false);
+ }
+
+ @Test
+ public void onWifiScan_isDeviceLockedTrue_callbackOnWifiScanFalse() {
+ reset(mInternetDialogCallback);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+ mInternetDialogController.onWifiScan(true);
+
+ verify(mInternetDialogCallback).onWifiScan(false);
+ }
+
+ @Test
+ public void onWifiScan_onWifiScanFalse_callbackOnWifiScanFalse() {
+ reset(mInternetDialogCallback);
+
+ mInternetDialogController.onWifiScan(false);
+
+ verify(mInternetDialogCallback).onWifiScan(false);
+ }
+
+ @Test
+ public void onWifiScan_onWifiScanTrue_callbackOnWifiScanTrue() {
+ reset(mInternetDialogCallback);
+
+ mInternetDialogController.onWifiScan(true);
+
+ verify(mInternetDialogCallback).onWifiScan(true);
+ }
+
+ @Test
public void setMergedCarrierWifiEnabledIfNeed_carrierProvisionsEnabled_doNothing() {
when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
.thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index 039e58a64eb5..916bb79d97b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -6,12 +6,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,9 +31,9 @@ import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -48,7 +46,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
@@ -613,66 +610,21 @@ public class InternetDialogTest extends SysuiTestCase {
}
@Test
- public void showProgressBar_wifiDisabled_hideProgressBar() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-
- mInternetDialog.showProgressBar();
-
- assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
- verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
- }
-
- @Test
- public void showProgressBar_deviceLocked_hideProgressBar() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-
- mInternetDialog.showProgressBar();
-
- assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
- verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
- }
-
- @Test
- public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
+ public void onWifiScan_isScanTrue_setProgressBarVisibleTrue() {
+ mInternetDialog.mIsProgressBarVisible = false;
- mInternetDialog.showProgressBar();
+ mInternetDialog.onWifiScan(true);
- // Show progress bar
assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
-
- ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mHandler).postDelayed(runnableCaptor.capture(),
- eq(InternetDialog.PROGRESS_DELAY_MS));
- runnableCaptor.getValue().run();
-
- // Then hide progress bar
- assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
}
@Test
- public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() {
- Mockito.reset(mHandler);
- when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
- mInternetDialog.mConnectedWifiEntry = null;
- mInternetDialog.mWifiEntriesCount = 0;
+ public void onWifiScan_isScanFalse_setProgressBarVisibleFalse() {
+ mInternetDialog.mIsProgressBarVisible = true;
- mInternetDialog.showProgressBar();
-
- // Show progress bar
- assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+ mInternetDialog.onWifiScan(false);
- ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mHandler).postDelayed(runnableCaptor.capture(),
- eq(InternetDialog.PROGRESS_DELAY_MS));
- runnableCaptor.getValue().run();
-
- // Then hide searching sub-title only
- assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
- assertThat(mInternetDialog.mIsSearchingHidden).isTrue();
+ assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
new file mode 100644
index 000000000000..c5d35245ba7c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.recordissue
+
+import android.app.Dialog
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.Button
+import android.widget.Switch
+import androidx.test.filters.SmallTest
+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.model.SysUiState
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class RecordIssueDialogDelegateTest : SysuiTestCase() {
+
+ private lateinit var dialog: SystemUIDialog
+ private lateinit var latch: CountDownLatch
+
+ @Before
+ fun setup() {
+ val dialogFactory =
+ SystemUIDialog.Factory(
+ context,
+ mock<FeatureFlags>(),
+ mock<SystemUIDialogManager>(),
+ mock<SysUiState>().apply {
+ whenever(setFlag(anyInt(), anyBoolean())).thenReturn(this)
+ },
+ mock<BroadcastDispatcher>(),
+ mock<DialogLaunchAnimator>()
+ )
+
+ latch = CountDownLatch(1)
+ dialog =
+ RecordIssueDialogDelegate(dialogFactory, mock()) { latch.countDown() }.createDialog()
+ dialog.show()
+ }
+
+ @After
+ fun teardown() {
+ dialog.dismiss()
+ }
+
+ @Test
+ fun dialog_hasCorrectUiElements_afterCreation() {
+ dialog.requireViewById<Switch>(R.id.screenrecord_switch)
+ dialog.requireViewById<Button>(R.id.issue_type_button)
+
+ assertThat(dialog.getButton(Dialog.BUTTON_POSITIVE).text)
+ .isEqualTo(context.getString(R.string.qs_record_issue_start))
+ assertThat(dialog.getButton(Dialog.BUTTON_NEGATIVE).text)
+ .isEqualTo(context.getString(R.string.cancel))
+ }
+
+ @Test
+ fun onStarted_isCalled_afterStartButtonIsClicked() {
+ dialog.getButton(Dialog.BUTTON_POSITIVE).callOnClick()
+ latch.await(1L, TimeUnit.MILLISECONDS)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
index 0f33aaf20195..2c7b60660165 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -56,6 +56,7 @@ import com.google.common.util.concurrent.Futures;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -138,6 +139,7 @@ public final class AppClipsActivityTest extends SysuiTestCase {
}
@Test
+ @Ignore("b/315848285")
public void screenshotDisplayed_userConsented_screenshotExportedSuccessfully() {
ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
assertThat(resultCode).isEqualTo(RESULT_OK);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 657f9127dc7e..e572dcca5a34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -23,6 +23,8 @@ import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -37,8 +39,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
import android.annotation.IdRes;
import android.content.ContentResolver;
import android.content.res.Configuration;
@@ -86,6 +86,7 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.view.LongPressHandlingView;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
@@ -402,6 +403,10 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
mPowerInteractor = keyguardInteractorDeps.getPowerInteractor();
when(mKeyguardTransitionInteractor.isInTransitionToStateWhere(any())).thenReturn(
StateFlowKt.MutableStateFlow(false));
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
new FakeDeviceProvisioningRepository(),
@@ -418,7 +423,9 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
new FakeConfigurationRepository(),
mContext,
- new ResourcesSplitShadeStateController()
+ new ResourcesSplitShadeStateController(),
+ mKeyguardInteractor,
+ deviceEntryUdfpsInteractor
),
mShadeRepository
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 5ffbe65d2c50..9d8b21464585 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -23,6 +23,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -54,6 +56,7 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -235,6 +238,11 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
mKeyguardSecurityModel,
mSelectedUserInteractor,
powerInteractor);
+
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
new FakeDeviceProvisioningRepository(),
@@ -251,7 +259,9 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- new ResourcesSplitShadeStateController()),
+ new ResourcesSplitShadeStateController(),
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor),
shadeRepository
)
);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index e723d7d0367b..eb5633b70f61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
import android.content.res.Resources;
@@ -41,6 +42,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
import com.android.systemui.flags.FeatureFlags;
@@ -275,6 +277,10 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
ResourcesSplitShadeStateController splitShadeStateController =
new ResourcesSplitShadeStateController();
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
deviceProvisioningRepository,
@@ -291,7 +297,9 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- splitShadeStateController),
+ splitShadeStateController,
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor),
mShadeRepository
)
);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index a3cff87e63b8..76c401547ce9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -30,8 +30,6 @@ import static org.mockito.Mockito.spy;
import android.app.ActivityManager;
import android.app.Notification;
-import android.os.Handler;
-import android.os.Looper;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -45,12 +43,12 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.FakeGlobalSettings;
+import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.time.SystemClock;
-import com.android.systemui.util.time.SystemClockImpl;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,27 +71,24 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
protected static final int TEST_STICKY_AUTO_DISMISS_TIME = 800;
// Number of notifications to use in tests requiring multiple notifications
private static final int TEST_NUM_NOTIFICATIONS = 4;
- protected static final int TEST_TIMEOUT_TIME = 2_000;
- protected final Runnable mTestTimeoutRunnable = () -> mTimedOut = true;
- protected Handler mTestHandler;
protected final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
- protected final SystemClock mSystemClock = new SystemClockImpl();
- protected boolean mTimedOut = false;
+ protected final FakeSystemClock mSystemClock = new FakeSystemClock();
+ protected final FakeExecutor mExecutor = new FakeExecutor(mSystemClock);
@Mock protected ExpandableNotificationRow mRow;
static {
assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME);
assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME);
- assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_TIMEOUT_TIME);
}
private static class TestableAlertingNotificationManager extends AlertingNotificationManager {
private AlertEntry mLastCreatedEntry;
- private TestableAlertingNotificationManager(Handler handler, SystemClock systemClock) {
- super(new HeadsUpManagerLogger(logcatLogBuffer()), handler, systemClock);
+ private TestableAlertingNotificationManager(SystemClock systemClock,
+ DelayableExecutor executor) {
+ super(new HeadsUpManagerLogger(logcatLogBuffer()), systemClock, executor);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
@@ -118,7 +113,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
}
protected AlertingNotificationManager createAlertingNotificationManager() {
- return new TestableAlertingNotificationManager(mTestHandler, mSystemClock);
+ return new TestableAlertingNotificationManager(mSystemClock, mExecutor);
}
protected StatusBarNotification createSbn(int id, Notification n) {
@@ -155,35 +150,6 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
return new NotificationEntryBuilder().setSbn(createSbn(id)).build();
}
- protected void verifyAlertingAtTime(AlertingNotificationManager anm, NotificationEntry entry,
- boolean shouldBeAlerting, int whenToCheckAlertingMillis, String whenCondition) {
- final Boolean[] wasAlerting = {null};
- final Runnable checkAlerting =
- () -> wasAlerting[0] = anm.isAlerting(entry.getKey());
-
- mTestHandler.postDelayed(checkAlerting, whenToCheckAlertingMillis);
- mTestHandler.postDelayed(mTestTimeoutRunnable, TEST_TIMEOUT_TIME);
- TestableLooper.get(this).processMessages(2);
-
- assertFalse("Test timed out", mTimedOut);
- if (shouldBeAlerting) {
- assertTrue("Should still be alerting after " + whenCondition, wasAlerting[0]);
- } else {
- assertFalse("Should not still be alerting after " + whenCondition, wasAlerting[0]);
- }
- assertFalse("Should not still be alerting after processing",
- anm.isAlerting(entry.getKey()));
- }
-
- @Before
- public void setUp() {
- mTestHandler = Handler.createAsync(Looper.myLooper());
- }
-
- @After
- public void tearDown() {
- mTestHandler.removeCallbacksAndMessages(null);
- }
@Test
public void testShowNotification_addsEntry() {
@@ -203,9 +169,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
final NotificationEntry entry = createEntry(/* id = */ 0);
alm.showNotification(entry);
-
- verifyAlertingAtTime(alm, entry, false, TEST_AUTO_DISMISS_TIME * 3 / 2,
- "auto dismiss time");
+ mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME * 3 / 2);
assertFalse(alm.isAlerting(entry.getKey()));
}
@@ -217,10 +181,8 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
alm.showNotification(entry);
- // Try to remove but defer, since the notification has not been shown long enough.
- final boolean removedImmediately = alm.removeNotification(entry.getKey(),
- false /* releaseImmediately */);
-
+ final boolean removedImmediately = alm.removeNotification(
+ entry.getKey(), /* releaseImmediately = */ false);
assertFalse(removedImmediately);
assertTrue(alm.isAlerting(entry.getKey()));
}
@@ -232,10 +194,8 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
alm.showNotification(entry);
- // Remove forcibly with releaseImmediately = true.
- final boolean removedImmediately = alm.removeNotification(entry.getKey(),
- true /* releaseImmediately */);
-
+ final boolean removedImmediately = alm.removeNotification(
+ entry.getKey(), /* releaseImmediately = */ true);
assertTrue(removedImmediately);
assertFalse(alm.isAlerting(entry.getKey()));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index dff91ddf559f..f25ce0aa5278 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -27,6 +27,7 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -53,6 +54,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSe
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.flow.emptyFlow
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -83,6 +85,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
FromPrimaryBouncerTransitionInteractor
@Mock lateinit var interactionJankMonitor: InteractionJankMonitor
@Mock lateinit var mockDarkAnimator: ObjectAnimator
+ @Mock lateinit var deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor
private lateinit var controller: StatusBarStateControllerImpl
private lateinit var uiEventLogger: UiEventLoggerFake
@@ -164,6 +167,8 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
mock(),
powerInteractor
)
+
+ whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(emptyFlow())
shadeInteractor =
ShadeInteractorImpl(
testScope.backgroundScope,
@@ -181,7 +186,9 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- ResourcesSplitShadeStateController()
+ ResourcesSplitShadeStateController(),
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor,
),
shadeRepository,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
index 3fef1d9832f0..5bc75e8b84c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
@@ -148,6 +148,24 @@ class AccessPointControllerImplTest : SysuiTestCase() {
}
@Test
+ fun onWifiEntriesChanged_reasonIsScanResults_fireWifiScanCallbackFalse() {
+ controller.addAccessPointCallback(callback)
+
+ controller.onWifiEntriesChanged(WifiPickerTracker.WIFI_ENTRIES_CHANGED_REASON_SCAN_RESULTS)
+
+ verify(callback).onWifiScan(false)
+ }
+
+ @Test
+ fun onScanRequested_fireWifiScanCallbackTrue() {
+ controller.addAccessPointCallback(callback)
+
+ controller.onScanRequested()
+
+ verify(callback).onWifiScan(true)
+ }
+
+ @Test
fun testOnNumSavedNetworksChangedDoesntTriggerCallback() {
controller.addAccessPointCallback(callback)
controller.onNumSavedNetworksChanged()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index bfa03eed57a0..8cf64a5aa8fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -48,7 +48,6 @@ import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -56,6 +55,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.log.LogAssertKt;
import com.android.systemui.statusbar.NotificationInteractionTracker;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.time.FakeSystemClock;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -129,10 +130,6 @@ public class ShadeListBuilderTest extends SysuiTestCase {
private Map<String, Integer> mNextIdMap = new ArrayMap<>();
private int mNextRank = 0;
- private Log.TerribleFailureHandler mOldWtfHandler = null;
- private Log.TerribleFailure mLastWtf = null;
- private int mWtfCount = 0;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -1756,20 +1753,19 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPreGroupFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the filter is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
// THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOutOfOrderPreGroupFilterInvalidationThrowsAfterTooManyRuns() {
// GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage,
NotifFilter filter = new PackageFilter(PACKAGE_1);
@@ -1778,20 +1774,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPreGroupFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the filter is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception IS thrown.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- try {
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- } finally {
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- }
- // THEN an exception IS thrown.
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
+ });
}
@Test
@@ -1803,26 +1799,30 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPreGroupFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the filter is invalidated
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times, the pipeline runs for a non-reentrant reason,
// and then the filter is invalidated MAX_CONSECUTIVE_REENTRANT_REBUILDS times again,
+
+ // THEN an exception is NOT thrown, but WTFs ARE logged.
+
addNotif(0, PACKAGE_2);
+
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- // Note: dispatchBuild itself triggers a non-reentrant pipeline run.
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
- // THEN an exception is NOT thrown, but WTFs ARE logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS * 2);
+ invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ // Note: dispatchBuild itself triggers a non-reentrant pipeline run.
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
@Test
- public void testOutOfOrderPrompterInvalidationDoesNotThrowBeforeTooManyRuns() {
+ public void testOutOfOrderPromoterInvalidationDoesNotThrowBeforeTooManyRuns() {
// GIVEN a NotifPromoter that gets invalidated during the sorting stage,
NotifPromoter promoter = new IdPromoter(47);
CountingInvalidator invalidator = new CountingInvalidator(promoter);
@@ -1830,22 +1830,22 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPromoter(promoter);
mListBuilder.addOnBeforeSortListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the promoter is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
- addNotif(0, PACKAGE_1);
- invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
// THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ addNotif(0, PACKAGE_1);
+ invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
- public void testOutOfOrderPrompterInvalidationThrowsAfterTooManyRuns() {
+ @Test
+ public void testOutOfOrderPromoterInvalidationThrowsAfterTooManyRuns() {
// GIVEN a NotifPromoter that gets invalidated during the sorting stage,
NotifPromoter promoter = new IdPromoter(47);
CountingInvalidator invalidator = new CountingInvalidator(promoter);
@@ -1853,20 +1853,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addPromoter(promoter);
mListBuilder.addOnBeforeSortListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the promoter is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception IS thrown.
+
addNotif(0, PACKAGE_1);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- try {
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- } finally {
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- }
- // THEN an exception IS thrown.
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
+ });
}
@Test
@@ -1878,20 +1878,21 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.setComparators(singletonList(comparator));
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the comparator is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception is NOT thrown directly, but a WTF IS logged.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- // THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOutOfOrderComparatorInvalidationThrowsAfterTooManyRuns() {
// GIVEN a NotifComparator that gets invalidated during the finalizing stage,
NotifComparator comparator = new HypeComparator(PACKAGE_1);
@@ -1900,16 +1901,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.setComparators(singletonList(comparator));
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the comparator is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception IS thrown.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- // THEN an exception IS thrown.
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
+ });
}
@Test
@@ -1921,20 +1926,21 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the PreRenderFilter is invalidated exactly
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
+
+ // THEN an exception is NOT thrown directly, but a WTF IS logged.
+
addNotif(0, PACKAGE_2);
invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- dispatchBuild();
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- // THEN an exception is NOT thrown directly, but a WTF IS logged.
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+ LogAssertKt.assertLogsWtfs(() -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testOutOfOrderPreRenderFilterInvalidationThrowsAfterTooManyRuns() {
// GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage,
NotifFilter filter = new PackageFilter(PACKAGE_1);
@@ -1943,59 +1949,22 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeRenderListListener(listener);
- interceptWtfs();
-
// WHEN we try to run the pipeline and the PreRenderFilter is invalidated more than
// MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
- addNotif(0, PACKAGE_2);
- invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- dispatchBuild();
- try {
- runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
- } finally {
- expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
- }
// THEN an exception IS thrown.
- }
-
- private void interceptWtfs() {
- assertNull(mOldWtfHandler);
- mLastWtf = null;
- mWtfCount = 0;
+ addNotif(0, PACKAGE_2);
+ invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
- mOldWtfHandler = Log.setWtfHandler((tag, e, system) -> {
- Log.e("ShadeListBuilderTest", "Observed WTF: " + e);
- mLastWtf = e;
- mWtfCount++;
+ LogAssertKt.assertLogsWtfs(() -> {
+ Assert.assertThrows(IllegalStateException.class, () -> {
+ dispatchBuild();
+ runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+ });
});
}
- private void expectNoWtfs() {
- assertNull(expectWtfs(0));
- }
-
- private Log.TerribleFailure expectWtf() {
- return expectWtfs(1);
- }
-
- private Log.TerribleFailure expectWtfs(int expectedWtfCount) {
- assertNotNull(mOldWtfHandler);
-
- Log.setWtfHandler(mOldWtfHandler);
- mOldWtfHandler = null;
-
- Log.TerribleFailure wtf = mLastWtf;
- int wtfCount = mWtfCount;
-
- mLastWtf = null;
- mWtfCount = 0;
-
- assertEquals(expectedWtfCount, wtfCount);
- return wtf;
- }
-
@Test
public void testStableOrdering() {
mStabilityManager.setAllowEntryReordering(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
index a07b5705d171..327a07d6179f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
@@ -20,57 +20,86 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class SharedNotificationContainerInteractorTest : SysuiTestCase() {
- private lateinit var configurationRepository: FakeConfigurationRepository
- private lateinit var underTest: SharedNotificationContainerInteractor
-
- @Before
- fun setUp() {
- configurationRepository = FakeConfigurationRepository()
- underTest =
- SharedNotificationContainerInteractor(
- configurationRepository,
- mContext,
- ResourcesSplitShadeStateController()
- )
- }
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val configurationRepository = kosmos.fakeConfigurationRepository
+ private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+ private val underTest = kosmos.sharedNotificationContainerInteractor
@Test
- fun validateConfigValues() = runTest {
- overrideResource(R.bool.config_use_split_notification_shade, true)
- overrideResource(R.bool.config_use_large_screen_shade_header, false)
- overrideResource(R.dimen.notification_panel_margin_horizontal, 0)
- overrideResource(R.dimen.notification_panel_margin_bottom, 10)
- overrideResource(R.dimen.notification_panel_margin_top, 10)
- overrideResource(R.dimen.large_screen_shade_header_height, 0)
- overrideResource(R.dimen.keyguard_split_shade_top_margin, 55)
-
- val dimens = collectLastValue(underTest.configurationBasedDimensions)
-
- configurationRepository.onAnyConfigurationChange()
- runCurrent()
-
- val lastDimens = dimens()!!
-
- assertThat(lastDimens.useSplitShade).isTrue()
- assertThat(lastDimens.useLargeScreenHeader).isFalse()
- assertThat(lastDimens.marginHorizontal).isEqualTo(0)
- assertThat(lastDimens.marginBottom).isGreaterThan(0)
- assertThat(lastDimens.marginTop).isGreaterThan(0)
- assertThat(lastDimens.marginTopLargeScreen).isEqualTo(0)
- assertThat(lastDimens.keyguardSplitShadeTopMargin).isEqualTo(55)
- }
+ fun validateConfigValues() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ overrideResource(R.bool.config_use_large_screen_shade_header, false)
+ overrideResource(R.dimen.notification_panel_margin_horizontal, 0)
+ overrideResource(R.dimen.notification_panel_margin_bottom, 10)
+ overrideResource(R.dimen.notification_panel_margin_top, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 0)
+ overrideResource(R.dimen.keyguard_split_shade_top_margin, 55)
+
+ val dimens = collectLastValue(underTest.configurationBasedDimensions)
+
+ configurationRepository.onAnyConfigurationChange()
+ runCurrent()
+
+ val lastDimens = dimens()!!
+
+ assertThat(lastDimens.useSplitShade).isTrue()
+ assertThat(lastDimens.useLargeScreenHeader).isFalse()
+ assertThat(lastDimens.marginHorizontal).isEqualTo(0)
+ assertThat(lastDimens.marginBottom).isGreaterThan(0)
+ assertThat(lastDimens.marginTop).isGreaterThan(0)
+ assertThat(lastDimens.marginTopLargeScreen).isEqualTo(0)
+ assertThat(lastDimens.keyguardSplitShadeTopMargin).isEqualTo(55)
+ }
+
+ @Test
+ fun useExtraShelfSpaceIsTrueWithUdfps() =
+ testScope.runTest {
+ val useExtraShelfSpace by collectLastValue(underTest.useExtraShelfSpace)
+
+ keyguardRepository.ambientIndicationVisible.value = true
+ fingerprintPropertyRepository.supportsUdfps()
+
+ assertThat(useExtraShelfSpace).isEqualTo(true)
+ }
+
+ @Test
+ fun useExtraShelfSpaceIsTrueWithRearFpsAndNoAmbientIndicationArea() =
+ testScope.runTest {
+ val useExtraShelfSpace by collectLastValue(underTest.useExtraShelfSpace)
+
+ keyguardRepository.ambientIndicationVisible.value = false
+ fingerprintPropertyRepository.supportsRearFps()
+
+ assertThat(useExtraShelfSpace).isEqualTo(true)
+ }
+
+ @Test
+ fun useExtraShelfSpaceIsFalseWithRearFpsAndAmbientIndicationArea() =
+ testScope.runTest {
+ val useExtraShelfSpace by collectLastValue(underTest.useExtraShelfSpace)
+
+ keyguardRepository.ambientIndicationVisible.value = true
+ fingerprintPropertyRepository.supportsRearFps()
+
+ assertThat(useExtraShelfSpace).isEqualTo(false)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index f0205b3f5974..36a471238c8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -332,8 +332,8 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
fun maxNotificationsOnLockscreen() =
testScope.runTest {
var notificationCount = 10
- val maxNotifications by
- collectLastValue(underTest.getMaxNotifications { notificationCount })
+ val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
+ val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
showLockscreen()
@@ -355,8 +355,8 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
fun maxNotificationsOnLockscreen_DoesNotUpdateWhenUserInteracting() =
testScope.runTest {
var notificationCount = 10
- val maxNotifications by
- collectLastValue(underTest.getMaxNotifications { notificationCount })
+ val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> notificationCount }
+ val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
showLockscreen()
@@ -390,7 +390,8 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
@Test
fun maxNotificationsOnShade() =
testScope.runTest {
- val maxNotifications by collectLastValue(underTest.getMaxNotifications { 10 })
+ val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> 10 }
+ val maxNotifications by collectLastValue(underTest.getMaxNotifications(calculateSpace))
// Show lockscreen with shade expanded
showLockscreenWithShadeExpanded()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 37ee32204f32..e1bd89fa7c34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -25,7 +26,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -45,11 +45,11 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
-import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -88,9 +88,9 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
StatusBarStateController statusBarStateController,
KeyguardBypassController keyguardBypassController,
ConfigurationController configurationController,
- Handler handler,
GlobalSettings globalSettings,
SystemClock systemClock,
+ DelayableExecutor executor,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
@@ -104,9 +104,10 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
groupManager,
visualStabilityProvider,
configurationController,
- handler,
+ mockExecutorHandler(executor),
globalSettings,
systemClock,
+ executor,
accessibilityManagerWrapper,
uiEventLogger,
javaAdapter,
@@ -126,9 +127,9 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
mStatusBarStateController,
mBypassController,
mConfigurationController,
- mTestHandler,
mGlobalSettings,
mSystemClock,
+ mExecutor,
mAccessibilityManagerWrapper,
mUiEventLogger,
mJavaAdapter,
@@ -142,7 +143,6 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
}
@Before
- @Override
public void setUp() {
when(mShadeInteractor.isAnyExpanded()).thenReturn(StateFlowKt.MutableStateFlow(false));
final AccessibilityManagerWrapper accessibilityMgr =
@@ -153,14 +153,6 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
mDependency.injectMockDependency(NotificationShadeWindowController.class);
mContext.getOrCreateTestableResources().addOverride(
R.integer.ambient_notification_extension_time, 500);
-
- super.setUp();
- }
-
- @After
- @Override
- public void tearDown() {
- super.tearDown();
}
@Test
@@ -224,8 +216,8 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
hmp.showNotification(entry);
hmp.extendHeadsUp();
+ mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2);
- final int pastNormalTimeMillis = TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2;
- verifyAlertingAtTime(hmp, entry, true, pastNormalTimeMillis, "normal time");
+ assertTrue(hmp.isAlerting(entry.getKey()));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 2940c398c315..4c893e3538a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy;
import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
+import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
import static com.google.common.truth.Truth.assertThat;
@@ -41,7 +42,6 @@ import android.app.Person;
import android.content.Context;
import android.content.Intent;
import android.graphics.Region;
-import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -56,11 +56,10 @@ import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AlertingNotificationManagerTest;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -77,7 +76,6 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
private static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
private static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
- private static final int TEST_A11Y_TIMEOUT_TIME = 3_000;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
@@ -87,25 +85,18 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME);
assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME);
assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
-
- assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_AUTO_DISMISS_TIME).isLessThan(
- TEST_TIMEOUT_TIME);
- assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(
- TEST_TIMEOUT_TIME);
- assertThat(TEST_TOUCH_ACCEPTANCE_TIME + TEST_A11Y_AUTO_DISMISS_TIME).isLessThan(
- TEST_A11Y_TIMEOUT_TIME);
}
private final class TestableHeadsUpManager extends BaseHeadsUpManager {
TestableHeadsUpManager(Context context,
HeadsUpManagerLogger logger,
- Handler handler,
+ DelayableExecutor executor,
GlobalSettings globalSettings,
SystemClock systemClock,
AccessibilityManagerWrapper accessibilityManagerWrapper,
UiEventLogger uiEventLogger) {
- super(context, logger, handler, globalSettings, systemClock,
- accessibilityManagerWrapper, uiEventLogger);
+ super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
+ executor, accessibilityManagerWrapper, uiEventLogger);
mTouchAcceptanceDelay = TEST_TOUCH_ACCEPTANCE_TIME;
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
@@ -183,7 +174,7 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
}
private BaseHeadsUpManager createHeadsUpManager() {
- return new TestableHeadsUpManager(mContext, mLogger, mTestHandler, mGlobalSettings,
+ return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings,
mSystemClock, mAccessibilityMgr, mUiEventLoggerFake);
}
@@ -234,18 +225,6 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
}
- @Before
- @Override
- public void setUp() {
- super.setUp();
- }
-
- @After
- @Override
- public void tearDown() {
- super.tearDown();
- }
-
@Test
public void testHunRemovedLogging() {
final BaseHeadsUpManager hum = createHeadsUpManager();
@@ -305,10 +284,9 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
useAccessibilityTimeout(false);
hum.showNotification(entry);
+ mSystemClock.advanceTime(TEST_TOUCH_ACCEPTANCE_TIME / 2 + TEST_AUTO_DISMISS_TIME);
- final int pastJustAutoDismissMillis =
- TEST_TOUCH_ACCEPTANCE_TIME / 2 + TEST_AUTO_DISMISS_TIME;
- verifyAlertingAtTime(hum, entry, true, pastJustAutoDismissMillis, "just auto dismiss");
+ assertTrue(hum.isAlerting(entry.getKey()));
}
@@ -319,10 +297,10 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
useAccessibilityTimeout(false);
hum.showNotification(entry);
+ mSystemClock.advanceTime(TEST_TOUCH_ACCEPTANCE_TIME
+ + (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2);
- final int pastDefaultTimeoutMillis = TEST_TOUCH_ACCEPTANCE_TIME
- + (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2;
- verifyAlertingAtTime(hum, entry, false, pastDefaultTimeoutMillis, "default timeout");
+ assertFalse(hum.isAlerting(entry.getKey()));
}
@@ -333,10 +311,10 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
useAccessibilityTimeout(false);
hum.showNotification(entry);
+ mSystemClock.advanceTime(TEST_TOUCH_ACCEPTANCE_TIME
+ + (TEST_AUTO_DISMISS_TIME + TEST_STICKY_AUTO_DISMISS_TIME) / 2);
- final int pastDefaultTimeoutMillis = TEST_TOUCH_ACCEPTANCE_TIME
- + (TEST_AUTO_DISMISS_TIME + TEST_STICKY_AUTO_DISMISS_TIME) / 2;
- verifyAlertingAtTime(hum, entry, true, pastDefaultTimeoutMillis, "default timeout");
+ assertTrue(hum.isAlerting(entry.getKey()));
}
@@ -347,18 +325,9 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
useAccessibilityTimeout(false);
hum.showNotification(entry);
+ mSystemClock.advanceTime(TEST_TOUCH_ACCEPTANCE_TIME + 2 * TEST_A11Y_AUTO_DISMISS_TIME);
- final int pastLongestAutoDismissMillis =
- TEST_TOUCH_ACCEPTANCE_TIME + 2 * TEST_A11Y_AUTO_DISMISS_TIME;
- final Boolean[] wasAlerting = {null};
- final Runnable checkAlerting =
- () -> wasAlerting[0] = hum.isAlerting(entry.getKey());
- mTestHandler.postDelayed(checkAlerting, pastLongestAutoDismissMillis);
- TestableLooper.get(this).processMessages(1);
-
- assertTrue("Should still be alerting past longest auto-dismiss", wasAlerting[0]);
- assertTrue("Should still be alerting after processing",
- hum.isAlerting(entry.getKey()));
+ assertTrue(hum.isAlerting(entry.getKey()));
}
@@ -369,10 +338,10 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
useAccessibilityTimeout(true);
hum.showNotification(entry);
+ mSystemClock.advanceTime(TEST_TOUCH_ACCEPTANCE_TIME
+ + (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2);
- final int pastDefaultTimeoutMillis = TEST_TOUCH_ACCEPTANCE_TIME
- + (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2;
- verifyAlertingAtTime(hum, entry, true, pastDefaultTimeoutMillis, "default timeout");
+ assertTrue(hum.isAlerting(entry.getKey()));
}
@@ -383,10 +352,10 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
useAccessibilityTimeout(true);
hum.showNotification(entry);
+ mSystemClock.advanceTime(TEST_TOUCH_ACCEPTANCE_TIME
+ + (TEST_STICKY_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2);
- final int pastStickyTimeoutMillis = TEST_TOUCH_ACCEPTANCE_TIME
- + (TEST_STICKY_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2;
- verifyAlertingAtTime(hum, entry, true, pastStickyTimeoutMillis, "sticky timeout");
+ assertTrue(hum.isAlerting(entry.getKey()));
}
@@ -398,18 +367,14 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
hum.showNotification(entry);
- // Try to remove but defer, since the notification has not been shown long enough.
final boolean removedImmediately = hum.removeNotification(
- entry.getKey(), false /* releaseImmediately */);
+ entry.getKey(), /* releaseImmediately = */ false);
+ assertFalse(removedImmediately);
+ assertTrue(hum.isAlerting(entry.getKey()));
- assertFalse("HUN should not be removed before minimum display time", removedImmediately);
- assertTrue("HUN should still be alerting before minimum display time",
- hum.isAlerting(entry.getKey()));
+ mSystemClock.advanceTime((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2);
- final int pastMinimumDisplayTimeMillis =
- (TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2;
- verifyAlertingAtTime(hum, entry, false, pastMinimumDisplayTimeMillis,
- "minimum display time");
+ assertFalse(hum.isAlerting(entry.getKey()));
}
@@ -420,32 +385,13 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
useAccessibilityTimeout(false);
hum.showNotification(entry);
+ mSystemClock.advanceTime((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2);
+
+ assertTrue(hum.isAlerting(entry.getKey()));
- // After the minimum display time:
- // 1. Check whether the notification is still alerting.
- // 2. Try to remove it and check whether the remove succeeded.
- // 3. Check whether it is still alerting after trying to remove it.
- final Boolean[] livedPastMinimumDisplayTime = {null};
- final Boolean[] removedAfterMinimumDisplayTime = {null};
- final Boolean[] livedPastRemoveAfterMinimumDisplayTime = {null};
- final Runnable pastMinimumDisplayTimeRunnable = () -> {
- livedPastMinimumDisplayTime[0] = hum.isAlerting(entry.getKey());
- removedAfterMinimumDisplayTime[0] = hum.removeNotification(
- entry.getKey(), /* releaseImmediately = */ false);
- livedPastRemoveAfterMinimumDisplayTime[0] = hum.isAlerting(entry.getKey());
- };
- final int pastMinimumDisplayTimeMillis =
- (TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2;
- mTestHandler.postDelayed(pastMinimumDisplayTimeRunnable, pastMinimumDisplayTimeMillis);
- // Wait until the minimum display time has passed before attempting removal.
- TestableLooper.get(this).processMessages(1);
-
- assertTrue("HUN should live past minimum display time",
- livedPastMinimumDisplayTime[0]);
- assertTrue("HUN should be removed immediately past minimum display time",
- removedAfterMinimumDisplayTime[0]);
- assertFalse("HUN should not live after being removed past minimum display time",
- livedPastRemoveAfterMinimumDisplayTime[0]);
+ final boolean removedImmediately = hum.removeNotification(
+ entry.getKey(), /* releaseImmediately = */ false);
+ assertTrue(removedImmediately);
assertFalse(hum.isAlerting(entry.getKey()));
}
@@ -457,10 +403,8 @@ public class BaseHeadsUpManagerTest extends AlertingNotificationManagerTest {
hum.showNotification(entry);
- // Remove forcibly with releaseImmediately = true.
final boolean removedImmediately = hum.removeNotification(
entry.getKey(), /* releaseImmediately = */ true);
-
assertTrue(removedImmediately);
assertFalse(hum.isAlerting(entry.getKey()));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 112368895888..b58a41c89a4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.theme;
+import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -90,6 +91,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
private static final int USER_SYSTEM = UserHandle.USER_SYSTEM;
private static final int USER_SECONDARY = 10;
+ private static final UserHandle MANAGED_USER_HANDLE = UserHandle.of(100);
+ private static final UserHandle PRIVATE_USER_HANDLE = UserHandle.of(101);
+
@Mock
private JavaAdapter mJavaAdapter;
@Mock
@@ -174,6 +178,14 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
Integer.toHexString(mColorScheme.getSeed() | 0xff000000)));
return overlay;
}
+
+ @VisibleForTesting
+ protected boolean isPrivateProfile(UserHandle userHandle) {
+ if (userHandle.getIdentifier() == PRIVATE_USER_HANDLE.getIdentifier()) {
+ return true;
+ }
+ return false;
+ }
};
mWakefulnessLifecycle.dispatchFinishedWakingUp();
@@ -675,7 +687,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
@Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -684,7 +697,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
reset(mDeviceProvisionedController);
when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
verify(mThemeOverlayApplier)
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -694,11 +708,25 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
reset(mDeviceProvisionedController);
when(mUserManager.isManagedProfile(anyInt())).thenReturn(true);
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
+ verify(mThemeOverlayApplier, never())
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
+ public void onPrivateProfileAdded_ignoresUntilStartComplete() {
+ mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ reset(mDeviceProvisionedController);
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
+ mBroadcastReceiver.getValue().onReceive(null,
+ (new Intent(Intent.ACTION_PROFILE_ADDED))
+ .putExtra(Intent.EXTRA_USER, PRIVATE_USER_HANDLE));
verify(mThemeOverlayApplier, never())
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
+
@Test
public void onWallpaperColorsChanged_firstEventBeforeUserSetup_shouldBeAccepted() {
// By default, on setup() we make this controller return that the user finished setup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
index 60fe7d2248e4..140e919d613f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
@@ -2,9 +2,8 @@ package com.android.systemui.user.domain.interactor
import android.content.pm.UserInfo
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.user.data.repository.FakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
@@ -24,15 +23,12 @@ class SelectedUserInteractorTest : SysuiTestCase() {
@Before
fun setUp() {
userRepository.setUserInfos(USER_INFOS)
- underTest =
- SelectedUserInteractor(
- userRepository,
- FakeFeatureFlagsClassic().apply { set(Flags.REFACTOR_GETCURRENTUSER, true) }
- )
+ underTest = SelectedUserInteractor(userRepository)
}
@Test
fun getSelectedUserIdReturnsId() {
+ mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER)
runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[0]) }
val actualId = underTest.getSelectedUserId()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 5b9b390eea2d..b217195000b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -29,6 +29,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -97,6 +99,7 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
@@ -465,6 +468,10 @@ public class BubblesTest extends SysuiTestCase {
ResourcesSplitShadeStateController splitShadeStateController =
new ResourcesSplitShadeStateController();
+ DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
+ mock(DeviceEntryUdfpsInteractor.class);
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+
mShadeInteractor =
new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
@@ -481,7 +488,9 @@ public class BubblesTest extends SysuiTestCase {
new SharedNotificationContainerInteractor(
configurationRepository,
mContext,
- splitShadeStateController),
+ splitShadeStateController,
+ keyguardInteractor,
+ deviceEntryUdfpsInteractor),
shadeRepository
)
);
diff --git a/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt b/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt
new file mode 100644
index 000000000000..b88f302cdfdd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.graphics.drawable
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.PixelFormat
+
+/**
+ * Stub drawable that does nothing. It's to be used in tests as a mock drawable and checked for the
+ * same instance
+ */
+class TestStubDrawable : Drawable() {
+
+ override fun draw(canvas: Canvas) = Unit
+ override fun setAlpha(alpha: Int) = Unit
+ override fun setColorFilter(colorFilter: ColorFilter?) = Unit
+ override fun getOpacity(): Int = PixelFormat.UNKNOWN
+
+ override fun equals(other: Any?): Boolean = this === other
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt
new file mode 100644
index 000000000000..607a4f3e1c0f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.accessibility.data.repository
+
+import android.os.UserHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeColorCorrectionRepository : ColorCorrectionRepository {
+ private val userMap = mutableMapOf<Int, MutableStateFlow<Boolean>>()
+
+ override fun isEnabled(userHandle: UserHandle): StateFlow<Boolean> {
+ return getFlow(userHandle.identifier)
+ }
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean {
+ getFlow(userHandle.identifier).value = isEnabled
+ return true
+ }
+
+ /** initializes the flow if already not */
+ private fun getFlow(userId: Int): MutableStateFlow<Boolean> {
+ return userMap.getOrPut(userId) { MutableStateFlow(false) }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt
new file mode 100644
index 000000000000..1c8bd3b58dfe
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.biometrics.data.repository
+
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeBiometricStatusRepository : BiometricStatusRepository {
+ private val _fingerprintAuthenticationReason =
+ MutableStateFlow<AuthenticationReason>(AuthenticationReason.NotRunning)
+ override val fingerprintAuthenticationReason: StateFlow<AuthenticationReason> =
+ _fingerprintAuthenticationReason.asStateFlow()
+
+ fun setFingerprintAuthenticationReason(reason: AuthenticationReason) {
+ _fingerprintAuthenticationReason.value = reason
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index f84481c55664..ff5179a7042c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -1,5 +1,6 @@
package com.android.systemui.bouncer.data.repository
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.dagger.SysUISingleton
@@ -113,7 +114,9 @@ class FakeKeyguardBouncerRepository @Inject constructor() : KeyguardBouncerRepos
_isBackButtonEnabled.value = isBackButtonEnabled
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
override fun setSideFpsShowing(isShowing: Boolean) {
+ SideFpsControllerRefactor.assertInLegacyMode()
_sideFpsShowing.value = isShowing
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
index 2cb17b5badc4..c85c27e277b4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
@@ -1,19 +1,47 @@
package com.android.systemui.communal.data.repository
import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.dagger.qualifiers.Background
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.test.TestScope
/** Fake implementation of [CommunalRepository]. */
+@OptIn(ExperimentalCoroutinesApi::class)
class FakeCommunalRepository(
+ @Background applicationScope: CoroutineScope = TestScope(),
override var isCommunalEnabled: Boolean = false,
override val desiredScene: MutableStateFlow<CommunalSceneKey> =
- MutableStateFlow(CommunalSceneKey.Blank)
+ MutableStateFlow(CommunalSceneKey.DEFAULT),
) : CommunalRepository {
override fun setDesiredScene(desiredScene: CommunalSceneKey) {
this.desiredScene.value = desiredScene
}
+ private val defaultTransitionState =
+ ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT)
+ private val _transitionState = MutableStateFlow<Flow<ObservableCommunalTransitionState>?>(null)
+ override val transitionState: StateFlow<ObservableCommunalTransitionState> =
+ _transitionState
+ .flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = defaultTransitionState,
+ )
+
+ override fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+ _transitionState.value = transitionState
+ }
+
fun setIsCommunalEnabled(value: Boolean) {
isCommunalEnabled = value
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
index c9160efb75a4..1d44929a20f0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -54,6 +54,11 @@ class FakeDeviceEntryFingerprintAuthRepository @Inject constructor() :
private var _authenticationStatus = MutableStateFlow<FingerprintAuthenticationStatus?>(null)
override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
get() = _authenticationStatus.filterNotNull()
+
+ private var _shouldUpdateIndicatorVisibility = MutableStateFlow(false)
+ override val shouldUpdateIndicatorVisibility: Flow<Boolean>
+ get() = _shouldUpdateIndicatorVisibility
+
fun setAuthenticationStatus(status: FingerprintAuthenticationStatus) {
_authenticationStatus.value = status
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 0e7c6625264c..4200f05ad64b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -41,6 +41,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
private val _deferKeyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow()
override val keyguardDone: Flow<KeyguardDone> = _deferKeyguardDone
+ private val _keyguardDoneAnimationsFinished: MutableSharedFlow<Unit> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+ override val keyguardDoneAnimationsFinished: Flow<Unit> = _keyguardDoneAnimationsFinished
+
private val _clockShouldBeCentered = MutableStateFlow<Boolean>(true)
override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered
@@ -121,6 +125,8 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
override val lastRootViewTapPosition: MutableStateFlow<Point?> = MutableStateFlow(null)
+ override val ambientIndicationVisible: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
override fun setQuickSettingsVisible(isVisible: Boolean) {
_isQuickSettingsVisible.value = isVisible
}
@@ -174,6 +180,10 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
_deferKeyguardDone.emit(timing)
}
+ override fun keyguardDoneAnimationsFinished() {
+ _keyguardDoneAnimationsFinished.tryEmit(Unit)
+ }
+
override fun setClockShouldBeCentered(shouldBeCentered: Boolean) {
_clockShouldBeCentered.value = shouldBeCentered
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
index 3d8ae1e9801a..3cabf0c07423 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
@@ -27,8 +27,6 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInte
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -57,12 +55,6 @@ object KeyguardDismissInteractorFactory {
keyguardRepository: FakeKeyguardRepository = FakeKeyguardRepository(),
bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(KeyguardUpdateMonitor::class.java),
- featureFlags: FakeFeatureFlagsClassic =
- FakeFeatureFlagsClassic().apply {
- set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, true)
- set(Flags.FULL_SCREEN_USER_SWITCHER, false)
- set(Flags.REFACTOR_GETCURRENTUSER, true)
- },
powerRepository: FakePowerRepository = FakePowerRepository(),
userRepository: FakeUserRepository = FakeUserRepository(),
): WithDependencies {
@@ -98,8 +90,7 @@ object KeyguardDismissInteractorFactory {
PowerInteractorFactory.create(
repository = powerRepository,
)
- val selectedUserInteractor =
- SelectedUserInteractor(repository = userRepository, flags = featureFlags)
+ val selectedUserInteractor = SelectedUserInteractor(repository = userRepository)
return WithDependencies(
trustRepository = trustRepository,
keyguardRepository = keyguardRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
index 10f9346aba14..6ccb3bc2812e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt
@@ -59,6 +59,17 @@ fun assertLogsWtf(
): TerribleFailureLog =
assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() }
+fun assertLogsWtfs(
+ message: String = "Expected Log.wtf to be called once or more",
+ loggingBlock: () -> Unit,
+): TerribleFailureLog = assertLogsWtf(message, allowMultiple = true, loggingBlock)
+
+@JvmOverloads
+fun assertLogsWtfs(
+ message: String = "Expected Log.wtf to be called once or more",
+ loggingRunnable: Runnable,
+): TerribleFailureLog = assertLogsWtfs(message) { loggingRunnable.run() }
+
/** The data passed to [TerribleFailureHandler.onTerribleFailure] */
data class TerribleFailureLog(
val tag: String,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
index 1cb2587e4e99..6332c1a8010d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
@@ -19,9 +19,14 @@ package com.android.systemui.qs
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.plugins.qs.QSFactory
+import com.android.systemui.qs.tiles.di.NewQSTileFactory
val Kosmos.instanceIdSequenceFake: InstanceIdSequenceFake by
Kosmos.Fixture { InstanceIdSequenceFake(0) }
val Kosmos.uiEventLogger: UiEventLoggerFake by Kosmos.Fixture { UiEventLoggerFake() }
val Kosmos.qsEventLogger: QsEventLoggerFake by
Kosmos.Fixture { QsEventLoggerFake(uiEventLogger, instanceIdSequenceFake) }
+
+var Kosmos.newQSTileFactory by Kosmos.Fixture<NewQSTileFactory>()
+var Kosmos.qsTileFactory by Kosmos.Fixture<QSFactory>()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.kt
new file mode 100644
index 000000000000..f01e3aaa7089
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/CustomTileStatePersisterKosmos.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.qs.external
+
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.customTileStatePersister: CustomTileStatePersister by
+ Kosmos.Fixture { fakeCustomTileStatePersister }
+val Kosmos.fakeCustomTileStatePersister by Kosmos.Fixture { FakeCustomTileStatePersister() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.kt
new file mode 100644
index 000000000000..f8ce707b0bb2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerFactoryKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.qs.external
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+/** Returns mocks */
+var Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by
+ Kosmos.Fixture { TileLifecycleManager.Factory { _, _ -> mock<TileLifecycleManager>() } }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt
new file mode 100644
index 000000000000..d93dd8d42721
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/model/RestoreProcessorsKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.qs.pipeline.data.model
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.pipeline.data.restoreprocessors.WorkTileRestoreProcessor
+
+val Kosmos.workTileRestoreProcessor by Kosmos.Fixture { WorkTileRestoreProcessor() }
+
+var Kosmos.restoreProcessors by
+ Kosmos.Fixture {
+ setOf(
+ workTileRestoreProcessor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt
new file mode 100644
index 000000000000..009148266143
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/QSPipelineRepositoryKosmos.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.qs.pipeline.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeTileSpecRepository by Kosmos.Fixture { FakeTileSpecRepository() }
+var Kosmos.tileSpecRepository: TileSpecRepository by Kosmos.Fixture { fakeTileSpecRepository }
+
+val Kosmos.fakeAutoAddRepository by Kosmos.Fixture { FakeAutoAddRepository() }
+var Kosmos.autoAddRepository: AutoAddRepository by Kosmos.Fixture { fakeAutoAddRepository }
+
+val Kosmos.fakeRestoreRepository by Kosmos.Fixture { FakeQSSettingsRestoredRepository() }
+var Kosmos.restoreRepository: QSSettingsRestoredRepository by
+ Kosmos.Fixture { fakeRestoreRepository }
+
+val Kosmos.fakeInstalledTilesRepository by
+ Kosmos.Fixture { FakeInstalledTilesComponentRepository() }
+var Kosmos.installedTilesRepository: InstalledTilesComponentRepository by
+ Kosmos.Fixture { fakeInstalledTilesRepository }
+
+val Kosmos.fakeCustomTileAddedRepository by Kosmos.Fixture { FakeCustomTileAddedRepository() }
+var Kosmos.customTileAddedRepository: CustomTileAddedRepository by
+ Kosmos.Fixture { fakeCustomTileAddedRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.kt
new file mode 100644
index 000000000000..35f178b62a08
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddablesKosmos.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.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.pipeline.data.model.workTileRestoreProcessor
+import com.android.systemui.settings.userTracker
+
+val Kosmos.workTileAutoAddable by
+ Kosmos.Fixture { WorkTileAutoAddable(userTracker, workTileRestoreProcessor) }
+
+var Kosmos.autoAddables by Kosmos.Fixture { setOf(workTileAutoAddable) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
index ebdd6fd7aac0..bf8f4da34d5b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
@@ -39,14 +39,18 @@ class FakeAutoAddable(
return getFlow(userId).asStateFlow().filterNotNull()
}
- suspend fun sendRemoveSignal(userId: Int) {
+ fun sendRemoveSignal(userId: Int) {
getFlow(userId).value = AutoAddSignal.Remove(spec)
}
- suspend fun sendAddSignal(userId: Int, position: Int = POSITION_AT_END) {
+ fun sendAddSignal(userId: Int, position: Int = POSITION_AT_END) {
getFlow(userId).value = AutoAddSignal.Add(spec, position)
}
+ fun sendRemoveTrackingSignal(userId: Int) {
+ getFlow(userId).value = AutoAddSignal.RemoveTracking(spec)
+ }
+
override val description: String
get() = "FakeAutoAddable($spec)"
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt
new file mode 100644
index 000000000000..5e8471c5575b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.qs.pipeline.domain.interactor
+
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.qs.pipeline.data.repository.autoAddRepository
+import com.android.systemui.qs.pipeline.domain.autoaddable.autoAddables
+import com.android.systemui.qs.pipeline.shared.logging.qsLogger
+
+val Kosmos.autoAddInteractor by
+ Kosmos.Fixture {
+ AutoAddInteractor(
+ autoAddables,
+ autoAddRepository,
+ dumpManager,
+ qsLogger,
+ applicationCoroutineScope,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt
new file mode 100644
index 000000000000..67df563ec5b0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorKosmos.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.qs.pipeline.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.qs.external.customTileStatePersister
+import com.android.systemui.qs.external.tileLifecycleManagerFactory
+import com.android.systemui.qs.newQSTileFactory
+import com.android.systemui.qs.pipeline.data.repository.customTileAddedRepository
+import com.android.systemui.qs.pipeline.data.repository.installedTilesRepository
+import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
+import com.android.systemui.qs.pipeline.shared.logging.qsLogger
+import com.android.systemui.qs.pipeline.shared.pipelineFlagsRepository
+import com.android.systemui.qs.qsTileFactory
+import com.android.systemui.settings.userTracker
+import com.android.systemui.user.data.repository.userRepository
+
+val Kosmos.currentTilesInteractor: CurrentTilesInteractor by
+ Kosmos.Fixture {
+ CurrentTilesInteractorImpl(
+ tileSpecRepository,
+ installedTilesRepository,
+ userRepository,
+ customTileStatePersister,
+ { newQSTileFactory },
+ qsTileFactory,
+ customTileAddedRepository,
+ tileLifecycleManagerFactory,
+ userTracker,
+ testDispatcher,
+ testDispatcher,
+ applicationCoroutineScope,
+ qsLogger,
+ pipelineFlagsRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.kt
new file mode 100644
index 000000000000..55c23d41e548
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorKosmos.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.qs.pipeline.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.qs.pipeline.data.model.restoreProcessors
+import com.android.systemui.qs.pipeline.data.repository.autoAddRepository
+import com.android.systemui.qs.pipeline.data.repository.restoreRepository
+import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
+import com.android.systemui.qs.pipeline.shared.logging.qsLogger
+
+val Kosmos.restoreReconciliationInteractor by
+ Kosmos.Fixture {
+ RestoreReconciliationInteractor(
+ tileSpecRepository,
+ autoAddRepository,
+ restoreRepository,
+ restoreProcessors,
+ qsLogger,
+ applicationCoroutineScope,
+ testDispatcher,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt
new file mode 100644
index 000000000000..961545aba4e8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagRepositoryKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.qs.pipeline.shared
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.pipelineFlagsRepository by Kosmos.Fixture { QSPipelineFlagsRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt
new file mode 100644
index 000000000000..7d52f5d8aa34
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.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.qs.pipeline.shared.logging
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+/** mock */
+var Kosmos.qsLogger: QSPipelineLogger by Kosmos.Fixture { mock<QSPipelineLogger>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt
new file mode 100644
index 000000000000..0357036d907c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.qs.tiles.impl.colorcorrection
+
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+
+val Kosmos.qsColorCorrectionTileConfig by
+ Kosmos.Fixture { QSAccessibilityModule.provideColorCorrectionTileConfig(qsEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt
index 8f972f52729f..18b3f47e3df7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakeCustomTilePackageUpdatesRepository.kt
@@ -16,17 +16,20 @@
package com.android.systemui.qs.tiles.impl.custom.data.repository
+import android.os.UserHandle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
class FakeCustomTilePackageUpdatesRepository : CustomTilePackageUpdatesRepository {
- private val mutablePackageChanges = MutableSharedFlow<Unit>()
+ private val mutablePackageChangesForUser = MutableSharedFlow<UserHandle>()
- override val packageChanges: Flow<Unit>
- get() = mutablePackageChanges
+ override fun getPackageChangesForUser(user: UserHandle): Flow<Unit> =
+ mutablePackageChangesForUser.filter { it == user }.map {}
- suspend fun emitPackageChange() {
- mutablePackageChanges.emit(Unit)
+ suspend fun emitPackageChange(user: UserHandle) {
+ mutablePackageChangesForUser.emit(user)
}
}
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 d78bcb93b256..0b41926ed13e 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
@@ -387,7 +387,7 @@ class SceneTestUtils(
}
fun selectedUserInteractor(): SelectedUserInteractor {
- return SelectedUserInteractor(userRepository, featureFlags)
+ return SelectedUserInteractor(userRepository)
}
fun bouncerActionButtonInteractor(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index 7494ccf32a2c..2ca338a3af9c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -72,6 +72,7 @@ class FakeUserTracker(
onBeforeUserSwitching()
onUserChanging()
onUserChanged()
+ onProfileChanged()
}
fun onBeforeUserSwitching(userId: Int = _userId) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.kt
new file mode 100644
index 000000000000..ffa86ff03ab1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserTrackerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.settings
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeUserTracker by Kosmos.Fixture { FakeUserTracker() }
+var Kosmos.userTracker: UserTracker by Kosmos.Fixture { fakeUserTracker }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
index c8013ef96fa7..862e52d7703f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
@@ -10,12 +10,12 @@ class FakeSmartspaceRepository(
override val isSmartspaceRemoteViewsEnabled = smartspaceRemoteViewsEnabled
- private val _lockscreenSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
+ private val _communalSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
MutableStateFlow(emptyList())
- override val lockscreenSmartspaceTargets: Flow<List<SmartspaceTarget>> =
- _lockscreenSmartspaceTargets
+ override val communalSmartspaceTargets: Flow<List<SmartspaceTarget>> =
+ _communalSmartspaceTargets
- fun setLockscreenSmartspaceTargets(targets: List<SmartspaceTarget>) {
- _lockscreenSmartspaceTargets.value = targets
+ fun setCommunalSmartspaceTargets(targets: List<SmartspaceTarget>) {
+ _communalSmartspaceTargets.value = targets
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt
index 3403227f6d27..13d577bde711 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import android.content.applicationContext
import com.android.systemui.common.ui.data.repository.configurationRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.policy.splitShadeStateController
@@ -27,5 +29,7 @@ val Kosmos.sharedNotificationContainerInteractor by
configurationRepository = configurationRepository,
context = applicationContext,
splitShadeStateController = splitShadeStateController,
+ keyguardInteractor = keyguardInteractor,
+ deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
index 427f92a7f514..89672f109657 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
@@ -16,9 +16,7 @@
package com.android.systemui.user.domain.interactor
-import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.user.data.repository.userRepository
-val Kosmos.selectedUserInteractor by
- Kosmos.Fixture { SelectedUserInteractor(userRepository, featureFlagsClassic) }
+val Kosmos.selectedUserInteractor by Kosmos.Fixture { SelectedUserInteractor(userRepository) }
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index b315f4a0f0c5..7fcef9c90812 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -76,6 +76,7 @@ import android.util.Size;
import android.view.Surface;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.camera.extensions.impl.AutoImageCaptureExtenderImpl;
import androidx.camera.extensions.impl.AutoPreviewExtenderImpl;
import androidx.camera.extensions.impl.BeautyImageCaptureExtenderImpl;
@@ -94,6 +95,7 @@ import androidx.camera.extensions.impl.PreviewExtenderImpl;
import androidx.camera.extensions.impl.PreviewExtenderImpl.ProcessorType;
import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
import androidx.camera.extensions.impl.ProcessResultImpl;
+import androidx.camera.extensions.impl.ProcessorImpl;
import androidx.camera.extensions.impl.RequestUpdateProcessorImpl;
import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.AutoAdvancedExtenderImpl;
@@ -101,6 +103,7 @@ import androidx.camera.extensions.impl.advanced.BeautyAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.BokehAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImpl;
import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl;
+import androidx.camera.extensions.impl.advanced.EyesFreeVideographyAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.HdrAdvancedExtenderImpl;
import androidx.camera.extensions.impl.advanced.ImageProcessorImpl;
import androidx.camera.extensions.impl.advanced.ImageReaderOutputConfigImpl;
@@ -112,6 +115,8 @@ import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
import androidx.camera.extensions.impl.advanced.SurfaceOutputConfigImpl;
+import com.android.internal.camera.flags.Flags;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -135,22 +140,28 @@ public class CameraExtensionsProxyService extends Service {
private static final String RESULTS_VERSION_PREFIX = "1.3";
// Support for various latency improvements
private static final String LATENCY_VERSION_PREFIX = "1.4";
- private static final String[] ADVANCED_VERSION_PREFIXES = {LATENCY_VERSION_PREFIX,
- ADVANCED_VERSION_PREFIX, RESULTS_VERSION_PREFIX };
- private static final String[] SUPPORTED_VERSION_PREFIXES = {LATENCY_VERSION_PREFIX,
- RESULTS_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, "1.1", NON_INIT_VERSION_PREFIX};
+ private static final String EFV_VERSION_PREFIX = "1.5";
+ private static final String[] ADVANCED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
+ LATENCY_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, RESULTS_VERSION_PREFIX };
+ private static final String[] SUPPORTED_VERSION_PREFIXES = {EFV_VERSION_PREFIX,
+ LATENCY_VERSION_PREFIX, RESULTS_VERSION_PREFIX, ADVANCED_VERSION_PREFIX, "1.1",
+ NON_INIT_VERSION_PREFIX};
private static final boolean EXTENSIONS_PRESENT = checkForExtensions();
private static final String EXTENSIONS_VERSION = EXTENSIONS_PRESENT ?
(new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION) : null;
private static final boolean ESTIMATED_LATENCY_API_SUPPORTED = checkForLatencyAPI();
private static final boolean LATENCY_IMPROVEMENTS_SUPPORTED = EXTENSIONS_PRESENT &&
- (EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX));
+ (EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX) ||
+ (EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX)));
+ private static final boolean EFV_SUPPORTED = EXTENSIONS_PRESENT &&
+ (EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX));
private static final boolean ADVANCED_API_SUPPORTED = checkForAdvancedAPI();
private static final boolean INIT_API_SUPPORTED = EXTENSIONS_PRESENT &&
(!EXTENSIONS_VERSION.startsWith(NON_INIT_VERSION_PREFIX));
private static final boolean RESULT_API_SUPPORTED = EXTENSIONS_PRESENT &&
(EXTENSIONS_VERSION.startsWith(RESULTS_VERSION_PREFIX) ||
- EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX));
+ EXTENSIONS_VERSION.startsWith(LATENCY_VERSION_PREFIX) ||
+ EXTENSIONS_VERSION.startsWith(EFV_VERSION_PREFIX));
private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>();
private CameraManager mCameraManager;
@@ -509,6 +520,167 @@ public class CameraExtensionsProxyService extends Service {
*/
public static Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> initializeExtension(
int extensionType) {
+ if (Flags.concertMode()) {
+ if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
+ // Basic extensions are deprecated starting with extension version 1.5
+ return new Pair<>(new PreviewExtenderImpl() {
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl getCaptureStage() {
+ return null;
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ return null;
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) { }
+
+ @Override
+ public void onDeInit() { }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
+ return null;
+ }
+
+ @Override
+ public int onSessionType() {
+ return 0;
+ }
+ }, new ImageCaptureExtenderImpl() {
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ return false;
+ }
+
+ @Override
+ public void init(String cameraId,
+ CameraCharacteristics cameraCharacteristics) { }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ return null;
+ }
+
+ @Override
+ public
+ List<androidx.camera.extensions.impl.CaptureStageImpl> getCaptureStages() {
+ return null;
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ return 0;
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ return null;
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ Size captureOutputSize) {
+ return null;
+ }
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ return null;
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ return null;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
+
+ @Override
+ public void onInit(String cameraId,
+ CameraCharacteristics cameraCharacteristics, Context context) { }
+
+ @Override
+ public void onDeInit() { }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
+ return null;
+ }
+
+ @Override
+ public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
+ return null;
+ }
+
+ @Override
+ public int onSessionType() {
+ return 0;
+ }
+ });
+ }
+ }
+
switch (extensionType) {
case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
return new Pair<>(new AutoPreviewExtenderImpl(),
@@ -533,6 +705,82 @@ public class CameraExtensionsProxyService extends Service {
* @hide
*/
public static AdvancedExtenderImpl initializeAdvancedExtensionImpl(int extensionType) {
+ if (Flags.concertMode()) {
+ if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
+ if (EFV_SUPPORTED) {
+ return new EyesFreeVideographyAdvancedExtenderImpl();
+ } else {
+ return new AdvancedExtenderImpl() {
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ return false;
+ }
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(String cameraId,
+ Size captureOutputSize, int imageFormat) {
+ return null;
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ String cameraId) {
+ return null;
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ String cameraId) {
+ return null;
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ return null;
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(String cameraId) {
+ return null;
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ return null;
+ }
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ return null;
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ return null;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
+ };
+ }
+ }
+ }
+
switch (extensionType) {
case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
return new AutoAdvancedExtenderImpl();
diff --git a/ravenwood/api-maintainers.md b/ravenwood/api-maintainers.md
index 30e899cd3ce3..d84cb6795fef 100644
--- a/ravenwood/api-maintainers.md
+++ b/ravenwood/api-maintainers.md
@@ -71,3 +71,24 @@ public class MyStruct {
The “replace” strategy described above is quite powerful, and can be used in creative ways to sidestep tricky underlying dependencies that aren’t ready yet.
For example, consider a constructor or static initializer that relies on unsupported functionality from another team. By factoring the unsupported logic into a dedicated method, that method can then be replaced under Ravenwood to offer baseline functionality.
+
+## Strategies for JNI
+
+At the moment, JNI isn't yet supported under Ravenwood, but you may still want to support APIs that are partially implemented with JNI. The current approach is to use the “replace” strategy to offer a pure-Java alternative implementation for any JNI-provided logic.
+
+Since this approach requires potentially complex re-implementation, it should only be considered for core infrastructure that is critical to unblocking widespread testing use-cases. Other less-common usages of JNI should instead wait for offical JNI support in the Ravenwood environment.
+
+When a pure-Java implementation grows too large or complex to host within the original class, the `@RavenwoodNativeSubstitutionClass` annotation can be used to host it in a separate source file:
+
+```
+@RavenwoodKeepWholeClass
+@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.MyComplexClass_host")
+public class MyComplexClass {
+ private static native void nativeDoThing(long nativePtr);
+...
+
+public class MyComplexClass_host {
+ public static void nativeDoThing(long nativePtr) {
+ // ...
+ }
+```
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index d175713eb92f..513c09587026 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -16,6 +16,8 @@
package android.platform.test.ravenwood;
+import static org.junit.Assert.fail;
+
import android.platform.test.annotations.IgnoreUnderRavenwood;
import org.junit.Assume;
@@ -36,6 +38,15 @@ public class RavenwoodRule implements TestRule {
private static final boolean IS_UNDER_RAVENWOOD = RavenwoodRuleImpl.isUnderRavenwood();
+ /**
+ * When probing is enabled, all tests will be unconditionally run under Ravenwood to detect
+ * cases where a test is able to pass despite being marked as {@code IgnoreUnderRavenwood}.
+ *
+ * This is typically helpful for internal maintainers discovering tests that had previously
+ * been ignored, but now have enough Ravenwood-supported functionality to be enabled.
+ */
+ private static final boolean ENABLE_PROBE_IGNORED = false; // DO NOT SUBMIT WITH TRUE
+
private static final int SYSTEM_UID = 1000;
private static final int NOBODY_UID = 9999;
private static final int FIRST_APPLICATION_UID = 10000;
@@ -97,26 +108,76 @@ public class RavenwoodRule implements TestRule {
return IS_UNDER_RAVENWOOD;
}
+ /**
+ * Test if the given {@link Description} has been marked with an {@link IgnoreUnderRavenwood}
+ * annotation, either at the method or class level.
+ */
+ private static boolean hasIgnoreUnderRavenwoodAnnotation(Description description) {
+ if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ return true;
+ } else if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
@Override
public Statement apply(Statement base, Description description) {
+ if (ENABLE_PROBE_IGNORED) {
+ return applyProbeIgnored(base, description);
+ } else {
+ return applyDefault(base, description);
+ }
+ }
+
+ /**
+ * Run the given {@link Statement} with no special treatment.
+ */
+ private Statement applyDefault(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
- if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) {
- Assume.assumeFalse(IS_UNDER_RAVENWOOD);
- }
- if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ if (hasIgnoreUnderRavenwoodAnnotation(description)) {
Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
- if (IS_UNDER_RAVENWOOD) {
- RavenwoodRuleImpl.init(RavenwoodRule.this);
- }
+
+ RavenwoodRuleImpl.init(RavenwoodRule.this);
try {
base.evaluate();
} finally {
- if (IS_UNDER_RAVENWOOD) {
- RavenwoodRuleImpl.reset(RavenwoodRule.this);
+ RavenwoodRuleImpl.reset(RavenwoodRule.this);
+ }
+ }
+ };
+ }
+
+ /**
+ * Run the given {@link Statement} with probing enabled. All tests will be unconditionally
+ * run under Ravenwood to detect cases where a test is able to pass despite being marked as
+ * {@code IgnoreUnderRavenwood}.
+ */
+ private Statement applyProbeIgnored(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ RavenwoodRuleImpl.init(RavenwoodRule.this);
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ if (hasIgnoreUnderRavenwoodAnnotation(description)) {
+ // This failure is expected, so eat the exception and report the
+ // assumption failure that test authors expect
+ Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
+ throw t;
+ } finally {
+ RavenwoodRuleImpl.reset(RavenwoodRule.this);
+ }
+
+ if (hasIgnoreUnderRavenwoodAnnotation(description) && IS_UNDER_RAVENWOOD) {
+ fail("Test was annotated with IgnoreUnderRavenwood, but it actually "
+ + "passed under Ravenwood; consider removing the annotation");
}
}
};
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index fb71e9d1ac6f..0ff6a1ad846b 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -22,12 +22,10 @@ public class RavenwoodRuleImpl {
}
public static void init(RavenwoodRule rule) {
- // Must be provided by impl to reference runtime internals
- throw new UnsupportedOperationException();
+ // No-op when running on a real device
}
public static void reset(RavenwoodRule rule) {
- // Must be provided by impl to reference runtime internals
- throw new UnsupportedOperationException();
+ // No-op when running on a real device
}
}
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 2ba5f6b05e26..13908f1732e1 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -1,8 +1,16 @@
# Only classes listed here can use the Ravenwood annotations.
com.android.internal.util.ArrayUtils
+com.android.internal.os.BatteryStatsHistory
+com.android.internal.os.BatteryStatsHistory$TraceDelegate
+com.android.internal.os.BatteryStatsHistory$VarintParceler
+com.android.internal.os.BatteryStatsHistoryIterator
+com.android.internal.os.Clock
com.android.internal.os.LongArrayMultiStateCounter
com.android.internal.os.LongArrayMultiStateCounter$LongArrayContainer
+com.android.internal.os.MonotonicClock
+com.android.internal.os.PowerStats
+com.android.internal.os.PowerStats$Descriptor
android.util.AtomicFile
android.util.DataUnit
@@ -25,8 +33,15 @@ android.util.TimeUtils
android.util.Xml
android.os.BatteryConsumer
+android.os.BatteryStats$HistoryItem
+android.os.BatteryStats$HistoryStepDetails
+android.os.BatteryStats$HistoryTag
+android.os.BatteryStats$ProcessStateChange
android.os.Binder
android.os.Binder$IdentitySupplier
+android.os.Broadcaster
+android.os.BundleMerger
+android.os.ConditionVariable
android.os.FileUtils
android.os.FileUtils$MemoryPipe
android.os.Handler
@@ -36,12 +51,15 @@ android.os.IBinder
android.os.Looper
android.os.Message
android.os.MessageQueue
+android.os.PackageTagsList
android.os.Parcel
android.os.Parcelable
android.os.Process
android.os.SystemClock
android.os.ThreadLocalWorkSource
+android.os.TimestampedValue
android.os.UserHandle
+android.os.WorkSource
android.content.ClipData
android.content.ClipData$Item
@@ -95,8 +113,6 @@ android.content.ContentProvider
com.android.server.LocalServices
-com.android.internal.os.SomeArgs
-
com.android.internal.util.BitUtils
com.android.internal.util.BitwiseInputStream
com.android.internal.util.BitwiseOutputStream
@@ -118,6 +134,23 @@ com.android.internal.util.QuickSelect
com.android.internal.util.RingBuffer
com.android.internal.util.StringPool
+com.android.internal.os.BinderCallHeavyHitterWatcher
+com.android.internal.os.BinderDeathDispatcher
+com.android.internal.os.BinderfsStatsReader
+com.android.internal.os.BinderLatencyBuckets
+com.android.internal.os.CachedDeviceState
+com.android.internal.os.Clock
+com.android.internal.os.CpuScalingPolicies
+com.android.internal.os.CpuScalingPolicyReader
+com.android.internal.os.KernelCpuThreadReader
+com.android.internal.os.LoggingPrintStream
+com.android.internal.os.LooperStats
+com.android.internal.os.MonotonicClock
+com.android.internal.os.ProcLocksReader
+com.android.internal.os.ProcStatsUtil
+com.android.internal.os.SomeArgs
+com.android.internal.os.StoragedUidIoStatsReader
+
com.google.android.collect.Lists
com.google.android.collect.Maps
com.google.android.collect.Sets
diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md
index de05777f01cd..5df827f11033 100644
--- a/ravenwood/test-authors.md
+++ b/ravenwood/test-authors.md
@@ -74,7 +74,7 @@ Once you’ve defined your test, you can use typical commands to execute it loca
$ atest --host MyTestsRavenwood
```
-> **Note:** There's a known bug where `atest` currently requires a connected device to run Ravenwood tests, but that device isn't used for testing. Using the `--host` argument above is a way to bypass this requirement until bug #312525698 is fixed.
+> **Note:** There's a known bug #312525698 where `atest` currently requires a connected device to run Ravenwood tests, but that device isn't used for testing. Using the `--host` argument above is a way to bypass this requirement until the bug is fixed.
You can also run your new tests automatically via `TEST_MAPPING` rules like this:
@@ -89,6 +89,8 @@ You can also run your new tests automatically via `TEST_MAPPING` rules like this
}
```
+> **Note:** There's a known bug #308854804 where `TEST_MAPPING` is not being applied, so we're currently planning to run all Ravenwood tests unconditionally in presubmit for changes to `frameworks/base/` and `cts/` until there is a better path forward.
+
## Strategies for feature flags
Ravenwood supports writing tests against logic that uses feature flags through the existing `SetFlagsRule` infrastructure maintained by the feature flagging team:
@@ -112,9 +114,9 @@ This naturally composes together well with any `RavenwoodRule` that your test ma
## Strategies for migration/bivalent tests
-Ravenwood aims to support tests that are written in a “bivalent” way, where the same test code can run on both a real Android device and under a Ravenwood environment.
+Ravenwood aims to support tests that are written in a “bivalent” way, where the same test code can be dual-compiled to run on both a real Android device and under a Ravenwood environment.
-In situations where a test method depends on API functionality not yet available under Ravenwood, we provide an annotation to quietly “ignore” that test under Ravenwood, while continuing to validate that test on real devices. Please note that your test must declare a `RavenwoodRule` for the annotation to take effect.
+In situations where a test method depends on API functionality not yet available under Ravenwood, we provide an annotation to quietly “ignore” that test under Ravenwood, while continuing to validate that test on real devices. The annotation can be applied to either individual methods or to an entire test class. Please note that your test class must declare a `RavenwoodRule` for the annotation to take effect.
Test authors are encouraged to provide a `blockedBy` or `reason` argument to help future maintainers understand why a test is being ignored, and under what conditions it might be supported in the future.
@@ -137,11 +139,39 @@ public class MyCodeTest {
}
```
+At the moment, the `android.content.res.Resources` subsystem isn't yet supported under Ravenwood, but you may still want to dual-compile test suites that depend on references to resources. Below is a strategy for supporting dual-compiliation, where you can "borrow" the generated resource symbols from your traditional `android_test` target:
+
+```
+android_test {
+ name: "MyTestsDevice",
+ resource_dirs: ["res"],
+...
+
+android_ravenwood_test {
+ name: "MyTestsRavenwood",
+ srcs: [
+ ":MyTestsDevice{.aapt.srcjar}",
+...
+```
+
## Strategies for unsupported APIs
As you write tests against Ravenwood, you’ll likely discover API dependencies that aren’t supported yet. Here’s a few strategies that can help you make progress:
-* Your code-under-test may benefit from subtle dependency refactoring to reduce coupling. (For example, providing a specific `File` argument instead of deriving it internally from a `Context`.)
+* Your code-under-test may benefit from subtle dependency refactoring to reduce coupling. (For example, providing a specific `File` argument instead of deriving paths internally from a `Context` or `Environment`.)
+ * One common use-case is providing a directory for your test to store temporary files, which can easily be accomplished using the `Files.createTempDirectory()` API which works on both physical devices and under Ravenwood:
+
+```
+import java.nio.file.Files;
+
+@RunWith(AndroidJUnit4.class)
+public class MyTest {
+ @Before
+ public void setUp() throws Exception {
+ File tempDir = Files.createTempDirectory("MyTest").toFile();
+...
+```
+
* Although mocking code that your team doesn’t own is a generally discouraged testing practice, it can be a valuable pressure relief valve when a dependency isn’t yet supported.
## Strategies for debugging test development
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index b8cf13b11534..e2488a51bba1 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -19,6 +19,9 @@ java_library_static {
defaults: [
"platform_service_defaults",
],
+ lint: {
+ error_checks: ["MissingPermissionAnnotation"],
+ },
srcs: [
":services.accessibility-sources",
"//frameworks/base/packages/SettingsLib/RestrictedLockUtils:SettingsLibRestrictedLockUtilsSrc",
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 0696807b3c8c..1d73843260cb 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -118,6 +118,7 @@ import java.util.Set;
* This class represents an accessibility client - either an AccessibilityService or a UiAutomation.
* It is responsible for behavior common to both types of clients.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub
implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter,
FingerprintGestureDispatcher.FingerprintGestureClient {
@@ -209,6 +210,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final ComponentName mComponentName;
int mGenericMotionEventSources;
+ int mObservedMotionEventSources;
// the events pending events to be dispatched to this service
final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>();
@@ -397,6 +399,19 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mNotificationTimeout = info.notificationTimeout;
mIsDefault = (info.flags & DEFAULT) != 0;
mGenericMotionEventSources = info.getMotionEventSources();
+ if (android.view.accessibility.Flags.motionEventObserving()) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING)
+ == PackageManager.PERMISSION_GRANTED) {
+ mObservedMotionEventSources = info.getObservedMotionEventSources();
+ } else {
+ Slog.e(
+ LOG_TAG,
+ "Observing motion events requires"
+ + " android.Manifest.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING.");
+ mObservedMotionEventSources = 0;
+ }
+ }
if (supportsFlagForNotImportantViews(info)) {
if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
@@ -1599,7 +1614,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int displayId = displays[i].getDisplayId();
onDisplayRemoved(displayId);
}
- if (Flags.cleanupA11yOverlays()) {
+ if (com.android.server.accessibility.Flags.cleanupA11yOverlays()) {
detachAllOverlays();
}
}
@@ -1919,6 +1934,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return (mGenericMotionEventSources & eventSourceWithoutClass) != 0;
}
+
/**
* Called by the invocation handler to notify the service that the
* state of magnification has changed.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 6cac6a47c77b..abcd8e2a2d7e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -57,6 +57,7 @@ import java.util.StringJoiner;
*
* NOTE: This class has to be created and poked only from the main thread.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
@@ -198,6 +199,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
// State tracking for generic MotionEvents is display-agnostic so we only need one.
private GenericMotionEventStreamState mGenericMotionEventStreamState;
private int mCombinedGenericMotionEventSources = 0;
+ private int mCombinedMotionEventObservedSources = 0;
private EventStreamState mKeyboardStreamState;
@@ -525,16 +527,33 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
if ((mEnabledFeatures & FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS) != 0) {
- addFirstEventHandler(displayId, new BaseEventStreamTransformation() {
- @Override
- public void onMotionEvent(MotionEvent event, MotionEvent rawEvent,
- int policyFlags) {
- if (!anyServiceWantsGenericMotionEvent(rawEvent)
- || !mAms.sendMotionEventToListeningServices(rawEvent)) {
- super.onMotionEvent(event, rawEvent, policyFlags);
- }
- }
- });
+ addFirstEventHandler(
+ displayId,
+ new BaseEventStreamTransformation() {
+ @Override
+ public void onMotionEvent(
+ MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ boolean passAlongEvent = true;
+ if (anyServiceWantsGenericMotionEvent(event)) {
+ // Some service wants this event, so try to deliver it to at least
+ // one service.
+ if (mAms.sendMotionEventToListeningServices(event)) {
+ // A service accepted this event, so prevent it from passing
+ // down the stream by default.
+ passAlongEvent = false;
+ }
+ // However, if a service is observing these events instead of
+ // consuming them then ensure
+ // it is always passed along to the next stage of the event stream.
+ if (anyServiceWantsToObserveMotionEvent(event)) {
+ passAlongEvent = true;
+ }
+ }
+ if (passAlongEvent) {
+ super.onMotionEvent(event, rawEvent, policyFlags);
+ }
+ }
+ });
}
if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
@@ -542,15 +561,14 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
|| ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP) != 0)
|| ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
final MagnificationGestureHandler magnificationGestureHandler =
- createMagnificationGestureHandler(displayId,
- displayContext);
+ createMagnificationGestureHandler(displayId, displayContext);
addFirstEventHandler(displayId, magnificationGestureHandler);
mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
}
if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
- MotionEventInjector injector = new MotionEventInjector(
- mContext.getMainLooper(), mAms.getTraceManager());
+ MotionEventInjector injector =
+ new MotionEventInjector(mContext.getMainLooper(), mAms.getTraceManager());
addFirstEventHandler(displayId, injector);
mMotionEventInjectors.put(displayId, injector);
}
@@ -923,6 +941,20 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
}
+ private boolean anyServiceWantsToObserveMotionEvent(MotionEvent event) {
+ // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
+ // touch exploration.
+ if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
+ && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
+ return false;
+ }
+ final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
+ return (mCombinedGenericMotionEventSources
+ & mCombinedMotionEventObservedSources
+ & eventSourceWithoutClass)
+ != 0;
+ }
+
private boolean anyServiceWantsGenericMotionEvent(MotionEvent event) {
// Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
// touch exploration.
@@ -938,6 +970,10 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
mCombinedGenericMotionEventSources = sources;
}
+ public void setCombinedMotionEventObservedSources(int sources) {
+ mCombinedMotionEventObservedSources = sources;
+ }
+
/**
* Keeps state of streams of events from all keyboard devices.
*/
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 440e99632c86..3d8d7b738233 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -195,6 +195,7 @@ import java.util.function.Predicate;
* event dispatch for {@link AccessibilityEvent}s generated across all processes
* on the device. Events are dispatched to {@link AccessibilityService}s.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class AccessibilityManagerService extends IAccessibilityManager.Stub
implements AbstractAccessibilityServiceConnection.SystemSupport,
AccessibilityUserState.ServiceInfoChangeListener,
@@ -2825,8 +2826,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
}
int combinedGenericMotionEventSources = 0;
+ int combinedMotionEventObservedSources = 0;
for (AccessibilityServiceConnection connection : userState.mBoundServices) {
combinedGenericMotionEventSources |= connection.mGenericMotionEventSources;
+ combinedMotionEventObservedSources |= connection.mObservedMotionEventSources;
}
if (combinedGenericMotionEventSources != 0) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS;
@@ -2845,6 +2848,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags);
mInputFilter.setCombinedGenericMotionEventSources(
combinedGenericMotionEventSources);
+ mInputFilter.setCombinedMotionEventObservedSources(
+ combinedMotionEventObservedSources);
} else {
if (mHasInputFilter) {
mHasInputFilter = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 40ca694dddd8..5ebe16115a4b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -65,6 +65,7 @@ import java.util.Set;
* passed to the service it represents as soon it is bound. It also serves as the
* connection for the service.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
private static final String LOG_TAG = "AccessibilityServiceConnection";
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index a525e7c64bc3..b119d7d117cd 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -34,6 +34,7 @@ import java.util.List;
* If we are stripping and/or replacing the actions from a window, we need to intercept the
* nodes heading back to the service and swap out the actions.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class ActionReplacingCallback extends IAccessibilityInteractionConnectionCallback.Stub {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "ActionReplacingCallback";
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
index c9ec16edc54e..e10e87c51d59 100644
--- a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -33,6 +33,7 @@ import java.util.List;
/**
* Encapsulate fingerprint gesture logic
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub
implements Handler.Callback{
private static final int MSG_REGISTER = 1;
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index ab01fc324ed2..6aa4702ec7d5 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -64,6 +64,7 @@ import java.util.Set;
*
* TODO(241429275): Initialize this when a proxy is registered.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class ProxyAccessibilityServiceConnection extends AccessibilityServiceConnection {
private static final String LOG_TAG = "ProxyAccessibilityServiceConnection";
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 53c629a9ed2d..f69104db7c10 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -245,6 +245,7 @@ class UiAutomationManager {
}
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private class UiAutomationService extends AbstractAccessibilityServiceConnection {
private final Handler mMainHandler;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index e6af54bd937c..e11c36a91830 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -922,6 +922,7 @@ public class MagnificationConnectionManager implements
disableWindowMagnification(displayId, true);
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private class ConnectionCallback extends IMagnificationConnectionCallback.Stub implements
IBinder.DeathRecipient {
private boolean mExpiredDeathRecipient = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
index c63784a79ffd..db5b3133169a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
@@ -246,6 +246,7 @@ class MagnificationConnectionWrapper {
return new RemoteAnimationCallback(callback, trace);
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private static class RemoteAnimationCallback extends
IRemoteMagnificationAnimationCallback.Stub {
private final MagnificationAnimationCallback mCallback;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 77a5e3db2aba..a4b28967e3b2 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -72,6 +72,7 @@ import android.content.pm.ServiceInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -559,10 +560,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(appUserId);
} else if (provider.maskedBySuspendedPackage) {
showBadge = mUserManager.hasBadge(appUserId);
- final String suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
+ final UserPackage suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
appInfo.packageName, appUserId);
// TODO(b/281839596): don't rely on platform always meaning suspended by admin.
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ if (suspendingPackage != null
+ && PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
appUserId, true);
} else {
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index ab678d93c665..b5130a1c4cfc 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -27,3 +27,10 @@ flag {
description: "Mitigation for view state reset to empty causing no save dialog to show issue"
bug: "297976948"
}
+
+flag {
+ name: "include_invisible_view_group_in_assist_structure"
+ namespace: "autofill"
+ description: "Mitigation for autofill providers miscalculating view visibility"
+ bug: "291795358"
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 23e7ce68c1d0..9fdf5c2d0fc1 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -92,9 +92,10 @@ class CompanionDeviceShellCommand extends ShellCommand {
int userId = getNextIntArgRequired();
String packageName = getNextArgRequired();
String address = getNextArgRequired();
+ String deviceProfile = getNextArg();
final MacAddress macAddress = MacAddress.fromString(address);
mService.createNewAssociation(userId, packageName, macAddress,
- null, null, false);
+ null, deviceProfile, false);
}
break;
@@ -350,7 +351,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" Print this help text.");
pw.println(" list USER_ID");
pw.println(" List all Associations for a user.");
- pw.println(" associate USER_ID PACKAGE MAC_ADDRESS");
+ pw.println(" associate USER_ID PACKAGE MAC_ADDRESS [DEVICE_PROFILE]");
pw.println(" Create a new Association.");
pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS");
pw.println(" Remove an existing Association.");
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 8dc6537d7e80..0d5cdcbe484c 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -439,6 +439,12 @@ public class VirtualDeviceManagerService extends SystemService {
if (associationInfo == null) {
throw new IllegalArgumentException("No association with ID " + associationId);
}
+ if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES
+ .contains(associationInfo.getDeviceProfile())
+ && Flags.persistentDeviceIdApi()) {
+ throw new IllegalArgumentException("Unsupported CDM Association device profile "
+ + associationInfo.getDeviceProfile() + " for virtual device creation.");
+ }
Objects.requireNonNull(params);
Objects.requireNonNull(activityListener);
Objects.requireNonNull(soundEffectListener);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 34787a390d48..145303df7b0b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -554,6 +554,10 @@ final class ContentCapturePerUserService
if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): no remote service");
return;
}
+ if (mRemoteService.getServiceInterface() == null) {
+ if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): remote service is dead or unbound");
+ return;
+ }
final ActivityEvent event = new ActivityEvent(activityId, componentName, type);
if (mMaster.verbose) Slog.v(mTag, "onActivityEvent(): " + event);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 20a3b9ada85d..f5a80d80f271 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -154,6 +154,7 @@ java_library_static {
static_libs: [
"android.frameworks.location.altitude-V1-java", // AIDL
+ "android.frameworks.vibrator-V1-java", // AIDL
"android.hardware.authsecret-V1.0-java",
"android.hardware.authsecret-V1-java",
"android.hardware.boot-V1.0-java", // HIDL
@@ -165,7 +166,7 @@ java_library_static {
"android.hardware.health-V1.0-java", // HIDL
"android.hardware.health-V2.0-java", // HIDL
"android.hardware.health-V2.1-java", // HIDL
- "android.hardware.health-V2-java", // AIDL
+ "android.hardware.health-V3-java", // AIDL
"android.hardware.health-translate-java",
"android.hardware.light-V1-java",
"android.hardware.security.rkp-V3-java",
@@ -199,6 +200,7 @@ java_library_static {
"notification_flags_lib",
"biometrics_flags_lib",
"am_flags_lib",
+ "com_android_systemui_shared_flags_lib",
"com_android_wm_shell_flags_lib",
"com.android.server.utils_aconfig-java",
"service-jobscheduler-deviceidle.flags-aconfig-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 09e79860b45c..cac2efba1c89 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -289,11 +289,11 @@ public abstract class PackageManagerInternal {
*
* @param suspendedPackage The package that has been suspended.
* @param userId The user for which to check.
- * @return Name of the package that suspended the given package. Returns {@code null} if the
- * given package is not currently suspended and the platform package name - i.e.
- * {@code "android"} - if the package was suspended by a device admin.
+ * @return User id and package name of the package that suspended the given package. Returns
+ * {@code null} if the given package is not currently suspended and the platform package name
+ * - i.e. {@code "android"} - if the package was suspended by a device admin.
*/
- public abstract String getSuspendingPackage(String suspendedPackage, int userId);
+ public abstract UserPackage getSuspendingPackage(String suspendedPackage, int userId);
/**
* Suspend or unsuspend packages upon admin request.
@@ -312,13 +312,13 @@ public abstract class PackageManagerInternal {
* suspended application.
*
* @param suspendedPackage The package that has been suspended.
- * @param suspendingPackage
+ * @param suspendingPackage The package responsible for suspension.
* @param userId The user for which to check.
* @return A {@link SuspendDialogInfo} object describing the dialog to be shown.
*/
@Nullable
public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId);
+ UserPackage suspendingPackage, int userId);
/**
* Gets any distraction flags set via
@@ -1168,14 +1168,14 @@ public abstract class PackageManagerInternal {
public abstract void clearBlockUninstallForUser(@UserIdInt int userId);
/**
- * Unsuspends all packages suspended by the given package for the user.
+ * Unsuspends all packages suspended by an admin for the user.
*/
- public abstract void unsuspendForSuspendingPackage(String suspendingPackage, int userId);
+ public abstract void unsuspendAdminSuspendedPackages(int userId);
/**
- * Returns {@code true} if the package is suspending any packages for the user.
+ * Returns {@code true} if an admin is suspending any packages for the user.
*/
- public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
+ public abstract boolean isAdminSuspendingAnyPackages(int userId);
/**
* Register to listen for loading progress of an installed package.
@@ -1426,14 +1426,19 @@ public abstract class PackageManagerInternal {
/**
* Checks if package is quarantined for a specific user.
+ *
+ * @throws PackageManager.NameNotFoundException if the package is not found
*/
- public abstract boolean isPackageQuarantined(@NonNull String packageName,
- @UserIdInt int userId);
+ public abstract boolean isPackageQuarantined(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
/**
* Checks if package is stopped for a specific user.
+ *
+ * @throws PackageManager.NameNotFoundException if the package is not found
*/
- public abstract boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId);
+ public abstract boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
/**
* Sends the PACKAGE_RESTARTED broadcast.
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 33726d17da62..5a44ac803cb4 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -974,6 +974,7 @@ public final class BatteryService extends SystemService {
unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
} break;
case "get": {
+ final int opts = parseOptions(shell);
final String key = shell.getNextArg();
if (key == null) {
pw.println("No property specified");
@@ -1007,11 +1008,17 @@ public final class BatteryService extends SystemService {
break;
case "current_now":
if (batteryServiceSupportCurrentAdbCommand()) {
+ if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ updateHealthInfo();
+ }
pw.println(mHealthInfo.batteryCurrentMicroamps);
}
break;
case "current_average":
if (batteryServiceSupportCurrentAdbCommand()) {
+ if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ updateHealthInfo();
+ }
pw.println(mHealthInfo.batteryCurrentAverageMicroamps);
}
break;
@@ -1125,6 +1132,14 @@ public final class BatteryService extends SystemService {
return 0;
}
+ private void updateHealthInfo() {
+ try {
+ mHealthServiceWrapper.scheduleUpdate();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to update health service data.", e);
+ }
+ }
+
private void setChargerAcOnline(boolean online, boolean forceUpdate) {
if (!mUpdatesStopped) {
copyV1Battery(mLastHealthInfo, mHealthInfo);
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 708da19232e1..5e9d1cbb32ca 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -110,6 +110,9 @@
},
{
"name": "FrameworksNetTests"
+ },
+ {
+ "name": "CtsSuspendAppsTestCases"
}
],
"presubmit-large": [
@@ -150,9 +153,6 @@
"name": "CtsPackageManagerTestCases"
},
{
- "name": "CtsSuspendAppsTestCases"
- },
- {
"name": "FrameworksServicesTests",
"options": [
{
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 3280afdf6703..627a62ee0496 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -42,6 +42,7 @@ import android.debug.AdbManager;
import android.debug.AdbNotifications;
import android.debug.AdbProtoEnums;
import android.debug.AdbTransportType;
+import android.debug.IAdbTransport;
import android.debug.PairDevice;
import android.net.ConnectivityManager;
import android.net.LocalSocket;
@@ -66,6 +67,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.service.adb.AdbDebuggingManagerProto;
+import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.Base64;
import android.util.Slog;
@@ -679,16 +681,17 @@ public class AdbDebuggingManager {
return;
}
- // Check for network change
- String bssid = wifiInfo.getBSSID();
- if (bssid == null || bssid.isEmpty()) {
- Slog.e(TAG, "Unable to get the wifi ap's BSSID. Disabling adbwifi.");
- Settings.Global.putInt(mContentResolver,
- Settings.Global.ADB_WIFI_ENABLED, 0);
- return;
- }
synchronized (mAdbConnectionInfo) {
- if (!bssid.equals(mAdbConnectionInfo.getBSSID())) {
+ // Check for network change
+ final String bssid = wifiInfo.getBSSID();
+ if (TextUtils.isEmpty(bssid)) {
+ Slog.e(TAG,
+ "Unable to get the wifi ap's BSSID. Disabling adbwifi.");
+ Settings.Global.putInt(mContentResolver,
+ Settings.Global.ADB_WIFI_ENABLED, 0);
+ return;
+ }
+ if (!TextUtils.equals(bssid, mAdbConnectionInfo.getBSSID())) {
Slog.i(TAG, "Detected wifi network change. Disabling adbwifi.");
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_WIFI_ENABLED, 0);
@@ -1397,7 +1400,7 @@ public class AdbDebuggingManager {
}
String bssid = wifiInfo.getBSSID();
- if (bssid == null || bssid.isEmpty()) {
+ if (TextUtils.isEmpty(bssid)) {
Slog.e(TAG, "Unable to get the wifi ap's BSSID.");
return null;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 71916843fe0b..df8f17ac9d7c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5175,6 +5175,8 @@ public final class ActiveServices {
return null;
}
+ final long startTimeNs = SystemClock.elapsedRealtimeNanos();
+
if (DEBUG_SERVICE) {
Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent + " fg=" + r.fgRequired);
}
@@ -5333,9 +5335,14 @@ public final class ActiveServices {
bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
+ mAm.mProcessList.getAppStartInfoTracker().handleProcessServiceStart(startTimeNs, app, r,
+ hostingRecord, true);
if (isolated) {
r.isolationHostProc = app;
}
+ } else {
+ mAm.mProcessList.getAppStartInfoTracker().handleProcessServiceStart(startTimeNs, app, r,
+ hostingRecord, false);
}
if (r.fgRequired) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ac173f3b5b7a..2ee39c577977 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -421,6 +421,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
@@ -468,7 +469,6 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.snapshot.PackageDataSnapshot;
import com.android.server.power.stats.BatteryStatsImpl;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
@@ -1103,9 +1103,51 @@ public class ActivityManagerService extends IActivityManager.Stub
private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
new ActivityMetricsLaunchObserver() {
+
+ @Override
+ public void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
+ synchronized (this) {
+ mProcessList.getAppStartInfoTracker().onIntentStarted(intent, timestampNanos);
+ }
+ }
+
@Override
- public void onActivityLaunched(long id, ComponentName name, int temperature) {
+ public void onIntentFailed(long id) {
+ mProcessList.getAppStartInfoTracker().onIntentFailed(id);
+ }
+
+ @Override
+ public void onActivityLaunched(long id, ComponentName name, int temperature, int userId) {
mAppProfiler.onActivityLaunched();
+ synchronized (ActivityManagerService.this) {
+ ProcessRecord record = null;
+ try {
+ record = getProcessRecordLocked(name.getPackageName(), mContext
+ .getPackageManager().getPackageUidAsUser(name.getPackageName(), 0,
+ userId));
+ } catch (NameNotFoundException nnfe) {
+ // Ignore, record will be lost.
+ }
+ mProcessList.getAppStartInfoTracker().onActivityLaunched(id, name, temperature,
+ record);
+ }
+ }
+
+ @Override
+ public void onActivityLaunchCancelled(long id) {
+ mProcessList.getAppStartInfoTracker().onActivityLaunchCancelled(id);
+ }
+
+ @Override
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos,
+ int launchMode) {
+ mProcessList.getAppStartInfoTracker().onActivityLaunchFinished(id, name,
+ timestampNanos, launchMode);
+ }
+
+ @Override
+ public void onReportFullyDrawn(long id, long timestampNanos) {
+ mProcessList.getAppStartInfoTracker().onReportFullyDrawn(id, timestampNanos);
}
};
@@ -4488,13 +4530,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
private void attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
-
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
long bindApplicationTimeMillis;
+ long bindApplicationTimeNanos;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
@@ -4698,6 +4740,7 @@ public class ActivityManagerService extends IActivityManager.Stub
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
bindApplicationTimeMillis = SystemClock.uptimeMillis();
+ bindApplicationTimeNanos = SystemClock.elapsedRealtimeNanos();
mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (mPlatformCompat != null) {
@@ -4754,6 +4797,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
app.setBindApplicationTime(bindApplicationTimeMillis);
+ mProcessList.getAppStartInfoTracker()
+ .reportBindApplicationTimeNanos(app, bindApplicationTimeNanos);
// Make app active after binding application or client may be running requests (e.g
// starting activities) before it is ready.
@@ -9799,12 +9844,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final int uid = enforceDumpPermissionForPackage(packageName, userId, callingUid,
"getHistoricalProcessStartReasons");
if (uid != INVALID_UID) {
- mProcessList.mAppStartInfoTracker.getStartInfo(
+ mProcessList.getAppStartInfoTracker().getStartInfo(
packageName, userId, callingPid, maxNum, results);
}
} else {
// If no package name is given, use the caller's uid as the filter uid.
- mProcessList.mAppStartInfoTracker.getStartInfo(
+ mProcessList.getAppStartInfoTracker().getStartInfo(
packageName, callingUid, callingPid, maxNum, results);
}
return new ParceledListSlice<ApplicationStartInfo>(results);
@@ -9822,7 +9867,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final int callingUid = Binder.getCallingUid();
- mProcessList.mAppStartInfoTracker.addStartInfoCompleteListener(listener, callingUid);
+ mProcessList.getAppStartInfoTracker().addStartInfoCompleteListener(listener, callingUid);
}
@@ -9836,7 +9881,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final int callingUid = Binder.getCallingUid();
- mProcessList.mAppStartInfoTracker.clearStartInfoCompleteListener(callingUid, true);
+ mProcessList.getAppStartInfoTracker().clearStartInfoCompleteListener(callingUid, true);
}
@Override
@@ -10138,7 +10183,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
- mProcessList.mAppStartInfoTracker.dumpHistoryProcessStartInfo(pw, dumpPackage);
+ mProcessList.getAppStartInfoTracker().dumpHistoryProcessStartInfo(pw, dumpPackage);
pw.println("-------------------------------------------------------------------------------");
mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
}
@@ -10541,7 +10586,7 @@ public class ActivityManagerService extends IActivityManager.Stub
dumpPackage = args[opti];
opti++;
}
- mProcessList.mAppStartInfoTracker.dumpHistoryProcessStartInfo(pw, dumpPackage);
+ mProcessList.getAppStartInfoTracker().dumpHistoryProcessStartInfo(pw, dumpPackage);
} else if ("exit-info".equals(cmd)) {
if (opti < args.length) {
dumpPackage = args[opti];
@@ -13831,6 +13876,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// activity manager to announce its creation.
public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId,
@BackupDestination int backupDestination) {
+ long startTimeNs = SystemClock.elapsedRealtimeNanos();
if (DEBUG_BACKUP) {
Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode
+ " targetUserId=" + targetUserId + " callingUid = " + Binder.getCallingUid()
@@ -13906,15 +13952,20 @@ public class ActivityManagerService extends IActivityManager.Stub
? new ComponentName(app.packageName, app.backupAgentName)
: new ComponentName("android", "FullBackupAgent");
- // startProcessLocked() returns existing proc's record if it's already running
- ProcessRecord proc = startProcessLocked(app.processName, app,
- false, 0,
- new HostingRecord(HostingRecord.HOSTING_TYPE_BACKUP, hostingName),
- ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false);
+ ProcessRecord proc = getProcessRecordLocked(app.processName, app.uid);
+ boolean isProcessStarted = proc != null;
+ if (!isProcessStarted) {
+ proc = startProcessLocked(app.processName, app,
+ false, 0,
+ new HostingRecord(HostingRecord.HOSTING_TYPE_BACKUP, hostingName),
+ ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false);
+ }
if (proc == null) {
Slog.e(TAG, "Unable to start backup agent process " + r);
return false;
}
+ mProcessList.getAppStartInfoTracker().handleProcessBackupStart(startTimeNs, proc, r,
+ !isProcessStarted);
// If the app is a regular app (uid >= 10000) and not the system server or phone
// process, etc, then mark it as being in full backup so that certain calls to the
@@ -18741,8 +18792,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// If the process is known as top app, set a hint so when the process is
// started, the top priority can be applied immediately to avoid cpu being
// preempted by other processes before attaching the process of top app.
- startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
- new HostingRecord(hostingType, hostingName, isTop),
+ final long startTimeNs = SystemClock.elapsedRealtimeNanos();
+ HostingRecord hostingRecord =
+ new HostingRecord(hostingType, hostingName, isTop);
+ ProcessRecord rec = getProcessRecordLocked(processName, info.uid);
+ ProcessRecord app = startProcessLocked(processName, info, knownToBeDead,
+ 0 /* intentFlags */, hostingRecord,
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index f3b2ef34ad6d..ae0cd65b2770 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1362,7 +1362,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
}
userId = user.id;
}
- mInternal.mProcessList.mAppStartInfoTracker
+ mInternal.mProcessList.getAppStartInfoTracker()
.clearHistoryProcessStartInfo(packageName, userId);
return 0;
}
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index edca74fae0e4..82e554e67b7e 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -22,11 +22,12 @@ import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import android.app.ActivityOptions;
+import android.annotation.NonNull;
import android.app.ApplicationStartInfo;
import android.app.Flags;
import android.app.IApplicationStartInfoCompleteListener;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -138,6 +139,15 @@ public final class AppStartInfoTracker {
/** The path to the historical proc start info file, persisted in the storage. */
@VisibleForTesting File mProcStartInfoFile;
+
+ /**
+ * Temporary list of records that have not been completed.
+ *
+ * Key is timestamp of launch from {@link #ActivityMetricsLaunchObserver}.
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<Long, ApplicationStartInfo> mInProgRecords = new ArrayMap<>();
+
AppStartInfoTracker() {
mCallbacks = new SparseArray<>();
mData = new ProcessMap<AppStartInfoContainer>();
@@ -174,68 +184,99 @@ public final class AppStartInfoTracker {
});
}
- void handleProcessColdStarted(long startTimeNs, HostingRecord hostingRecord,
- ProcessRecord app) {
+ void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
synchronized (mLock) {
if (!mEnabled) {
return;
}
ApplicationStartInfo start = new ApplicationStartInfo();
- addBaseFieldsFromProcessRecord(start, app);
start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_FORK, app.getStartElapsedTime());
- start.setStartType(ApplicationStartInfo.START_TYPE_COLD);
- start.setReason(ApplicationStartInfo.START_REASON_OTHER);
- addStartInfoLocked(start);
+ start.setIntent(intent);
+ start.setStartType(ApplicationStartInfo.START_TYPE_UNSET);
+ start.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_LAUNCH, timestampNanos);
+ if (intent != null && intent.getCategories() != null
+ && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+ start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER);
+ } else {
+ start.setReason(ApplicationStartInfo.START_REASON_START_ACTIVITY);
+ }
+ mInProgRecords.put(timestampNanos, start);
}
}
- public void handleProcessActivityWarmOrHotStarted(long startTimeNs,
- ActivityOptions activityOptions, Intent intent) {
+ void onIntentFailed(long id) {
synchronized (mLock) {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo();
- start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs);
- start.setIntent(intent);
- start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER);
- if (activityOptions != null) {
- start.setProcessName(activityOptions.getPackageName());
+ if (!mInProgRecords.containsKey(id)) {
+ return;
}
- start.setStartType(ApplicationStartInfo.START_TYPE_WARM);
- if (intent != null && intent.getCategories() != null
- && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER);
+ mInProgRecords.get(id).setStartupState(ApplicationStartInfo.STARTUP_STATE_ERROR);
+ mInProgRecords.remove(id);
+ }
+ }
+
+ void onActivityLaunched(long id, ComponentName name, long temperature, ProcessRecord app) {
+ synchronized (mLock) {
+ if (!mEnabled) {
+ return;
+ }
+ if (!mInProgRecords.containsKey(id)) {
+ return;
+ }
+ if (app != null) {
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.setStartType((int) temperature);
+ addBaseFieldsFromProcessRecord(info, app);
+ addStartInfoLocked(info);
} else {
- start.setReason(ApplicationStartInfo.START_REASON_START_ACTIVITY);
+ mInProgRecords.remove(id);
}
- addStartInfoLocked(start);
}
}
- public void handleProcessActivityStartedFromRecents(long startTimeNs,
- ActivityOptions activityOptions) {
+ void onActivityLaunchCancelled(long id) {
synchronized (mLock) {
if (!mEnabled) {
return;
}
- ApplicationStartInfo start = new ApplicationStartInfo();
- start.setStartupState(ApplicationStartInfo.STARTUP_STATE_STARTED);
- start.addStartupTimestamp(
- ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs);
- if (activityOptions != null) {
- start.setIntent(activityOptions.getResultData());
- start.setProcessName(activityOptions.getPackageName());
+ if (!mInProgRecords.containsKey(id)) {
+ return;
}
- start.setReason(ApplicationStartInfo.START_REASON_LAUNCHER_RECENTS);
- start.setStartType(ApplicationStartInfo.START_TYPE_WARM);
- addStartInfoLocked(start);
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.setStartupState(ApplicationStartInfo.STARTUP_STATE_ERROR);
+ mInProgRecords.remove(id);
+ }
+ }
+
+ void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos,
+ int launchMode) {
+ synchronized (mLock) {
+ if (!mEnabled) {
+ return;
+ }
+ if (!mInProgRecords.containsKey(id)) {
+ return;
+ }
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.setStartupState(ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN);
+ info.setLaunchMode(launchMode);
+ }
+ }
+
+ void onReportFullyDrawn(long id, long timestampNanos) {
+ synchronized (mLock) {
+ if (!mEnabled) {
+ return;
+ }
+ if (!mInProgRecords.containsKey(id)) {
+ return;
+ }
+ ApplicationStartInfo info = mInProgRecords.get(id);
+ info.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN,
+ timestampNanos);
+ mInProgRecords.remove(id);
}
}
@@ -347,7 +388,8 @@ public final class AppStartInfoTracker {
ApplicationStartInfo.START_TIMESTAMP_APPLICATION_ONCREATE);
}
- void reportBindApplicationTimeNanos(ProcessRecord app, long timeNs) {
+ /** Report a bind application timestamp to add to {@link ApplicationStartInfo}. */
+ public void reportBindApplicationTimeNanos(ProcessRecord app, long timeNs) {
addTimestampToStart(app, timeNs,
ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION);
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f8f3d82556fa..ace2cfd8a307 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -33,6 +33,7 @@ import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
import android.annotation.SuppressLint;
+import android.app.AlarmManager;
import android.app.StatsManager;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -427,13 +428,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mPowerStatsStore = new PowerStatsStore(systemDir, mHandler, aggregatedPowerStatsConfig);
mPowerStatsAggregator = new PowerStatsAggregator(aggregatedPowerStatsConfig,
mStats.getHistory());
- final long aggregatedPowerStatsSpanDuration = context.getResources().getInteger(
- com.android.internal.R.integer.config_aggregatedPowerStatsSpanDuration);
- final long powerStatsAggregationPeriod = context.getResources().getInteger(
- com.android.internal.R.integer.config_powerStatsAggregationPeriod);
- mPowerStatsScheduler = new PowerStatsScheduler(context, mPowerStatsAggregator,
- aggregatedPowerStatsSpanDuration, powerStatsAggregationPeriod, mPowerStatsStore,
- Clock.SYSTEM_CLOCK, mMonotonicClock, mHandler, mStats);
+ mPowerStatsScheduler = createPowerStatsScheduler(mContext);
PowerStatsExporter powerStatsExporter =
new PowerStatsExporter(mPowerStatsStore, mPowerStatsAggregator);
mBatteryUsageStatsProvider = new BatteryUsageStatsProvider(context,
@@ -445,6 +440,23 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mConfigFile = new AtomicFile(new File(systemDir, "battery_usage_stats_config"));
}
+ private PowerStatsScheduler createPowerStatsScheduler(Context context) {
+ final long aggregatedPowerStatsSpanDuration = context.getResources().getInteger(
+ com.android.internal.R.integer.config_aggregatedPowerStatsSpanDuration);
+ final long powerStatsAggregationPeriod = context.getResources().getInteger(
+ com.android.internal.R.integer.config_powerStatsAggregationPeriod);
+ PowerStatsScheduler.AlarmScheduler alarmScheduler =
+ (triggerAtMillis, tag, onAlarmListener, aHandler) -> {
+ AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME, triggerAtMillis, tag,
+ onAlarmListener, aHandler);
+ };
+ return new PowerStatsScheduler(mStats::schedulePowerStatsSampleCollection,
+ mPowerStatsAggregator, aggregatedPowerStatsSpanDuration,
+ powerStatsAggregationPeriod, mPowerStatsStore, alarmScheduler, Clock.SYSTEM_CLOCK,
+ mMonotonicClock, () -> mStats.getHistory().getStartTime(), mHandler);
+ }
+
private AggregatedPowerStatsConfig getAggregatedPowerStatsConfig() {
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_CPU)
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 903cb7bcfaed..982076dd7c9a 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -30,7 +30,6 @@ import android.widget.WidgetFlags;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import java.util.ArrayList;
import java.util.HashMap;
@@ -164,12 +163,6 @@ final class CoreSettingsObserver extends ContentObserver {
WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT));
sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
- SystemUiDeviceConfigFlags.KEY_REMOTEVIEWS_ADAPTER_CONVERSION, boolean.class,
- SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT));
-
- sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
TextFlags.NAMESPACE, TextFlags.ENABLE_NEW_CONTEXT_MENU,
TextFlags.KEY_ENABLE_NEW_CONTEXT_MENU, boolean.class,
TextFlags.ENABLE_NEW_CONTEXT_MENU_DEFAULT));
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4ff34b1d7faa..3156e9da0ae9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -498,7 +498,7 @@ public final class ProcessList {
/** Manages the {@link android.app.ApplicationStartInfo} records. */
@GuardedBy("mAppStartInfoTracker")
- final AppStartInfoTracker mAppStartInfoTracker = new AppStartInfoTracker();
+ private final AppStartInfoTracker mAppStartInfoTracker = new AppStartInfoTracker();
/**
* The currently running SDK sandbox processes for a uid.
@@ -1523,6 +1523,10 @@ public final class ProcessList {
return mCachedRestoreLevel;
}
+ AppStartInfoTracker getAppStartInfoTracker() {
+ return mAppStartInfoTracker;
+ }
+
/**
* Set the out-of-memory badness adjustment for a process.
* If {@code pid <= 0}, this method will be a no-op.
@@ -2572,6 +2576,7 @@ public final class ProcessList {
boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.uptimeMillis();
+ final long startTimeNs = SystemClock.elapsedRealtimeNanos();
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b2082d9e8dc0..b4cd6a31291e 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -401,7 +401,7 @@ class ProcessRecord implements WindowProcessListener {
/**
* All about the process state info (proc state, oom adj score) in this process.
*/
- final ProcessStateRecord mState;
+ ProcessStateRecord mState;
/**
* All about the state info of the optimizer when the process is cached.
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index c7a560b52a01..9f31f375dafe 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -226,20 +226,28 @@ public class AmbientContextManagerService extends
List<AmbientContextManagerPerUserService> serviceList =
new ArrayList<>(serviceNames.length);
- if (serviceNames.length == 2) {
+ if (serviceNames.length == 2
+ && !isDefaultService(serviceNames[0])
+ && !isDefaultWearableService(serviceNames[1])) {
Slog.i(TAG, "Not using default services, "
+ "services provided for testing should be exactly two services.");
- if (!isDefaultService(serviceNames[0]) && !isDefaultWearableService(serviceNames[1])) {
- serviceList.add(new DefaultAmbientContextManagerPerUserService(
- this, mLock, resolvedUserId,
- AmbientContextManagerPerUserService.ServiceType.DEFAULT, serviceNames[0]));
- serviceList.add(new WearableAmbientContextManagerPerUserService(
- this, mLock, resolvedUserId,
- AmbientContextManagerPerUserService.ServiceType.WEARABLE,
- serviceNames[1]));
- }
+ serviceList.add(
+ new DefaultAmbientContextManagerPerUserService(
+ this,
+ mLock,
+ resolvedUserId,
+ AmbientContextManagerPerUserService.ServiceType.DEFAULT,
+ serviceNames[0]));
+ serviceList.add(
+ new WearableAmbientContextManagerPerUserService(
+ this,
+ mLock,
+ resolvedUserId,
+ AmbientContextManagerPerUserService.ServiceType.WEARABLE,
+ serviceNames[1]));
return serviceList;
- } else {
+ }
+ if (serviceNames.length > 2) {
Slog.i(TAG, "Incorrect number of services provided for testing.");
}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 824bdd4ccb79..32d5cf587e0c 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.app;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.EXTRA_REPLACING;
+import static android.server.app.Flags.gameDefaultFrameRate;
import static com.android.internal.R.styleable.GameModeConfig_allowGameAngleDriver;
import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscaling;
@@ -28,6 +29,7 @@ import static com.android.internal.R.styleable.GameModeConfig_supportsPerformanc
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.Manifest;
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -66,11 +68,13 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PermissionEnforcer;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
@@ -138,6 +142,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
static final int WRITE_GAME_MODE_INTERVENTION_LIST_FILE = 6;
static final int WRITE_DELAY_MILLIS = 10 * 1000; // 10 seconds
static final int LOADING_BOOST_MAX_DURATION = 5 * 1000; // 5 seconds
+ static final String PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED =
+ "persist.graphics.game_default_frame_rate.enabled";
+ static final String PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE =
+ "ro.surface_flinger.game_default_frame_rate_override";
private static final String PACKAGE_NAME_MSG_KEY = "packageName";
private static final String USER_ID_MSG_KEY = "userId";
@@ -154,7 +162,6 @@ public final class GameManagerService extends IGameManagerService.Stub {
private final PackageManager mPackageManager;
private final UserManager mUserManager;
private final PowerManagerInternal mPowerManagerInternal;
- private final File mSystemDir;
@VisibleForTesting
final AtomicFile mGameModeInterventionListFile;
private DeviceConfigListener mDeviceConfigListener;
@@ -175,28 +182,57 @@ public final class GameManagerService extends IGameManagerService.Stub {
final MyUidObserver mUidObserver;
@GuardedBy("mUidObserverLock")
private final Set<Integer> mForegroundGameUids = new HashSet<>();
+ private final GameManagerServiceSystemPropertiesWrapper mSysProps;
+ private float mGameDefaultFrameRateValue;
+
+ @VisibleForTesting
+ static class Injector {
+ public GameManagerServiceSystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return new GameManagerServiceSystemPropertiesWrapper() {
+ @Override
+ public String get(String key, String def) {
+ return SystemProperties.get(key, def);
+ }
+ @Override
+ public boolean getBoolean(String key, boolean def) {
+ return SystemProperties.getBoolean(key, def);
+ }
+
+ @Override
+ public int getInt(String key, int def) {
+ return SystemProperties.getInt(key, def);
+ }
+
+ @Override
+ public void set(String key, String val) {
+ SystemProperties.set(key, val);
+ }
+ };
+ }
+ }
public GameManagerService(Context context) {
this(context, createServiceThread().getLooper());
}
GameManagerService(Context context, Looper looper) {
- this(context, looper, Environment.getDataDirectory());
+ this(context, looper, Environment.getDataDirectory(), new Injector());
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- GameManagerService(Context context, Looper looper, File dataDir) {
+ GameManagerService(Context context, Looper looper, File dataDir, Injector injector) {
+ super(PermissionEnforcer.fromContext(context));
mContext = context;
mHandler = new SettingsHandler(looper);
mPackageManager = mContext.getPackageManager();
mUserManager = mContext.getSystemService(UserManager.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mSystemDir = new File(dataDir, "system");
- mSystemDir.mkdirs();
- FileUtils.setPermissions(mSystemDir.toString(),
+ File systemDir = new File(dataDir, "system");
+ systemDir.mkdirs();
+ FileUtils.setPermissions(systemDir.toString(),
FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
-1, -1);
- mGameModeInterventionListFile = new AtomicFile(new File(mSystemDir,
+ mGameModeInterventionListFile = new AtomicFile(new File(systemDir,
GAME_MODE_INTERVENTION_LIST_FILE_NAME));
FileUtils.setPermissions(mGameModeInterventionListFile.getBaseFile().getAbsolutePath(),
FileUtils.S_IRUSR | FileUtils.S_IWUSR
@@ -220,6 +256,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
} catch (RemoteException e) {
Slog.w(TAG, "Could not register UidObserver");
}
+
+ mSysProps = injector.createSystemPropertiesWrapper();
}
@Override
@@ -1521,6 +1559,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, false);
Slog.v(TAG, "Game power mode OFF (game manager service start/restart)");
mPowerManagerInternal.setPowerMode(Mode.GAME, false);
+
+ mGameDefaultFrameRateValue = (float) mSysProps.getInt(
+ PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE, 60);
+ Slog.v(TAG, "Game Default Frame Rate : " + mGameDefaultFrameRateValue);
}
private void sendUserMessage(int userId, int what, String eventForLog, int delayMillis) {
@@ -1588,7 +1630,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
final float fps = 0.0f;
final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
- setOverrideFrameRate(uid, fps);
+ setGameModeFrameRateOverride(uid, fps);
} catch (PackageManager.NameNotFoundException e) {
return;
}
@@ -1620,7 +1662,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
final float fps = modeConfig.getFps();
final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
- setOverrideFrameRate(uid, fps);
+ setGameModeFrameRateOverride(uid, fps);
} catch (PackageManager.NameNotFoundException e) {
return;
}
@@ -2159,14 +2201,69 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
@VisibleForTesting
- void setOverrideFrameRate(int uid, float frameRate) {
- nativeSetOverrideFrameRate(uid, frameRate);
+ void setGameModeFrameRateOverride(int uid, float frameRate) {
+ nativeSetGameModeFrameRateOverride(uid, frameRate);
+ }
+
+ @VisibleForTesting
+ void setGameDefaultFrameRateOverride(int uid, float frameRate) {
+ Slog.v(TAG, "setDefaultFrameRateOverride : " + uid + " , " + frameRate);
+ nativeSetGameDefaultFrameRateOverride(uid, frameRate);
+ }
+
+ private float getGameDefaultFrameRate() {
+ final boolean isGameDefaultFrameRateEnabled;
+ float gameDefaultFrameRate = 0.0f;
+ synchronized (mLock) {
+ isGameDefaultFrameRateEnabled =
+ mSysProps.getBoolean(
+ PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED, true);
+ }
+ if (gameDefaultFrameRate()) {
+ gameDefaultFrameRate = isGameDefaultFrameRateEnabled
+ ? mGameDefaultFrameRateValue : 0.0f;
+ }
+ return gameDefaultFrameRate;
+ }
+
+ @Override
+ @EnforcePermission(Manifest.permission.MANAGE_GAME_MODE)
+ public void toggleGameDefaultFrameRate(boolean isEnabled) {
+ toggleGameDefaultFrameRate_enforcePermission();
+ if (gameDefaultFrameRate()) {
+ Slog.v(TAG, "toggleGameDefaultFrameRate : " + isEnabled);
+ this.toggleGameDefaultFrameRateUnchecked(isEnabled);
+ }
+ }
+
+ private void toggleGameDefaultFrameRateUnchecked(boolean isEnabled) {
+ // Update system properties.
+ // Here we only need to immediately update games that are in the foreground.
+ // We will update game default frame rate when a game comes into foreground in
+ // MyUidObserver.
+ synchronized (mLock) {
+ if (isEnabled) {
+ mSysProps.set(
+ PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED, "true");
+ } else {
+ mSysProps.set(
+ PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED, "false");
+ }
+ }
+
+ // Update all foreground games' frame rate.
+ synchronized (mUidObserverLock) {
+ for (int uid : mForegroundGameUids) {
+ setGameDefaultFrameRateOverride(uid, getGameDefaultFrameRate());
+ }
+ }
}
/**
* load dynamic library for frame rate overriding JNI calls
*/
- private static native void nativeSetOverrideFrameRate(int uid, float frameRate);
+ private static native void nativeSetGameModeFrameRateOverride(int uid, float frameRate);
+ private static native void nativeSetGameDefaultFrameRateOverride(int uid, float frameRate);
final class MyUidObserver extends UidObserver {
@Override
@@ -2179,6 +2276,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
synchronized (mUidObserverLock) {
+
if (procState != ActivityManager.PROCESS_STATE_TOP) {
disableGameMode(uid);
return;
@@ -2198,6 +2296,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
Slog.v(TAG, "Game power mode ON (process state was changed to foreground)");
mPowerManagerInternal.setPowerMode(Mode.GAME, true);
}
+ setGameDefaultFrameRateOverride(uid, getGameDefaultFrameRate());
mForegroundGameUids.add(uid);
}
}
diff --git a/services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java b/services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java
new file mode 100644
index 000000000000..afacedaac11b
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameManagerServiceSystemPropertiesWrapper.java
@@ -0,0 +1,67 @@
+/*
+ * 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.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemProperties;
+/**
+ * Wrapper interface to access {@link SystemProperties}.
+ *
+ * @hide
+ */
+interface GameManagerServiceSystemPropertiesWrapper {
+ /**
+ * Get the String value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+ * string otherwise
+ */
+ @NonNull
+ String get(@NonNull String key, @Nullable String def);
+ /**
+ * Get the Boolean value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, not parsable
+ * or an empty string otherwise
+ */
+ @NonNull
+ boolean getBoolean(@NonNull String key, boolean def);
+
+ /**
+ * Get the Integer value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, not parsable
+ * or an empty string otherwise
+ */
+ @NonNull
+ int getInt(@NonNull String key, int def);
+ /**
+ * Set the value for the given {@code key} to {@code val}.
+ *
+ * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
+ * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
+ * SELinux. libc will log the underlying reason.
+ */
+ void set(@NonNull String key, @Nullable String val);
+}
diff --git a/services/core/java/com/android/server/app/flags.aconfig b/services/core/java/com/android/server/app/flags.aconfig
new file mode 100644
index 000000000000..f2e4783bd9eb
--- /dev/null
+++ b/services/core/java/com/android/server/app/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.server.app"
+
+flag {
+ name: "game_default_frame_rate"
+ namespace: "game"
+ description: "This flag guards the new behavior with the addition of Game Default Frame Rate feature."
+ bug: "286084594"
+ is_fixed_read_only: true
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 34cfdfaa7974..d138f24e7dc7 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -896,7 +896,8 @@ public class AudioDeviceInventory {
if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
boolean codecChange = false;
if (btInfo.mProfile == BluetoothProfile.A2DP
- || btInfo.mProfile == BluetoothProfile.LE_AUDIO) {
+ || btInfo.mProfile == BluetoothProfile.LE_AUDIO
+ || btInfo.mProfile == BluetoothProfile.LE_AUDIO_BROADCAST) {
if (di.mDeviceCodecFormat != codec) {
di.mDeviceCodecFormat = codec;
mConnectedDevices.replace(key, di);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 44cb1367928d..290bb7e92c69 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5106,7 +5106,7 @@ public class AudioService extends IAudioService.Stub
private void setMasterMuteInternalNoCallerCheck(
boolean mute, int flags, int userId, String eventSource) {
if (DEBUG_VOL) {
- Log.d(TAG, TextUtils.formatSimple("Master mute %s, %d, user=%d from %s",
+ Log.d(TAG, TextUtils.formatSimple("Master mute %s, flags 0x%x, userId=%d from %s",
mute, flags, userId, eventSource));
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 401dc88669ec..8075618be200 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -324,7 +324,8 @@ public class BtHelper {
// AUDIO_FORMAT_DEFAULT as native audio policy manager expects a specific audio format
// only if audio HW module selection based on format is supported for the device type.
if (!(profile == BluetoothProfile.A2DP
- || (profile == BluetoothProfile.LE_AUDIO && isLeOutput))) {
+ || (isLeOutput && ((profile == BluetoothProfile.LE_AUDIO)
+ || (profile == BluetoothProfile.LE_AUDIO_BROADCAST))))) {
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
@AudioSystem.AudioFormatNativeEnumForBtCodec int codec =
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0629e6373b6e..dafea9a199fd 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -36,6 +36,7 @@ import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.ComponentInfoInternal;
@@ -385,6 +386,26 @@ public class AuthService extends SystemService {
}
@Override
+ public void registerAuthenticationStateListener(AuthenticationStateListener listener)
+ throws RemoteException {
+ checkInternalPermission();
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService != null) {
+ fingerprintService.registerAuthenticationStateListener(listener);
+ }
+ }
+
+ @Override
+ public void unregisterAuthenticationStateListener(AuthenticationStateListener listener)
+ throws RemoteException {
+ checkInternalPermission();
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService != null) {
+ fingerprintService.unregisterAuthenticationStateListener(listener);
+ }
+ }
+
+ @Override
public void invalidateAuthenticatorIds(int userId, int fromSensorId,
IInvalidationCallback callback) throws RemoteException {
checkInternalPermission();
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index a47135fd032f..f9568ea9d72b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -27,7 +27,7 @@ import android.hardware.biometrics.AuthenticateOptions;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.os.IBinder;
import android.os.RemoteException;
import android.security.KeyStore;
@@ -430,19 +430,19 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions>
return mLockoutTracker;
}
- protected int getShowOverlayReason() {
+ protected int getRequestReason() {
if (isKeyguard()) {
- return BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
+ return BiometricRequestConstants.REASON_AUTH_KEYGUARD;
} else if (isBiometricPrompt()) {
// BP reason always takes precedent over settings, since callers from within
// settings can always invoke BP.
- return BiometricOverlayConstants.REASON_AUTH_BP;
+ return BiometricRequestConstants.REASON_AUTH_BP;
} else if (isSettings()) {
// This is pretty much only for FingerprintManager#authenticate usage from
// FingerprintSettings.
- return BiometricOverlayConstants.REASON_AUTH_SETTINGS;
+ return BiometricRequestConstants.REASON_AUTH_SETTINGS;
} else {
- return BiometricOverlayConstants.REASON_AUTH_OTHER;
+ return BiometricRequestConstants.REASON_AUTH_OTHER;
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java
new file mode 100644
index 000000000000..58635353c780
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java
@@ -0,0 +1,108 @@
+/*
+ * 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.biometrics.sensors;
+
+import android.annotation.NonNull;
+import android.hardware.biometrics.AuthenticationStateListener;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Low-level callback interface between BiometricManager and AuthService. Allows core system
+ * services (e.g. SystemUI) to register and unregister listeners for updates about the current
+ * state of biometric authentication.
+ * @hide */
+public class AuthenticationStateListeners implements IBinder.DeathRecipient {
+
+ private static final String TAG = "AuthenticationStateListeners";
+
+ @NonNull
+ private final CopyOnWriteArrayList<AuthenticationStateListener> mAuthenticationStateListeners =
+ new CopyOnWriteArrayList<>();
+
+ /**
+ * Enables clients to register an AuthenticationStateListener for updates about the current
+ * state of biometric authentication.
+ * @param listener listener to register
+ */
+ public void registerAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ mAuthenticationStateListeners.add(listener);
+ try {
+ listener.asBinder().linkToDeath(this, 0 /* flags */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death", e);
+ }
+ }
+
+ /**
+ * Enables clients to unregister an AuthenticationStateListener.
+ * @param listener listener to register
+ */
+ public void unregisterAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ mAuthenticationStateListeners.remove(listener);
+ }
+
+ /**
+ * Defines behavior in response to authentication starting
+ * @param requestReason reason from [BiometricRequestConstants.RequestReason] for requesting
+ * authentication starting
+ */
+ public void onAuthenticationStarted(int requestReason) {
+ for (AuthenticationStateListener listener: mAuthenticationStateListeners) {
+ try {
+ listener.onAuthenticationStarted(requestReason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in notifying listener that authentication "
+ + "started", e);
+ }
+ }
+ }
+
+ /**
+ * Defines behavior in response to authentication stopping
+ */
+ public void onAuthenticationStopped() {
+ for (AuthenticationStateListener listener: mAuthenticationStateListeners) {
+ try {
+ listener.onAuthenticationStopped();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in notifying listener that authentication "
+ + "stopped", e);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Do nothing, handled below
+ }
+
+ @Override
+ public void binderDied(IBinder who) {
+ Slog.w(TAG, "Callback binder died: " + who);
+ if (mAuthenticationStateListeners.removeIf(listener -> listener.asBinder().equals(who))) {
+ Slog.w(TAG, "Removed dead listener for " + who);
+ } else {
+ Slog.w(TAG, "No dead listeners found");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 483ce75eae98..2c4d30b622ad 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -19,7 +19,7 @@ package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.FingerprintManager;
import android.os.IBinder;
import android.os.RemoteException;
@@ -135,14 +135,14 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> implements En
return true;
}
- protected int getOverlayReasonFromEnrollReason(@FingerprintManager.EnrollReason int reason) {
+ protected int getRequestReasonFromEnrollReason(@FingerprintManager.EnrollReason int reason) {
switch (reason) {
case FingerprintManager.ENROLL_FIND_SENSOR:
- return BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+ return BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR;
case FingerprintManager.ENROLL_ENROLL:
- return BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
+ return BiometricRequestConstants.REASON_ENROLL_ENROLLING;
default:
- return BiometricOverlayConstants.REASON_UNKNOWN;
+ return BiometricRequestConstants.REASON_UNKNOWN;
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index aeb6b6e2a907..3d20efc88c77 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -16,9 +16,11 @@
package com.android.server.biometrics.sensors;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
@@ -42,6 +44,8 @@ public final class SensorOverlays {
private static final String TAG = "SensorOverlays";
@NonNull private final Optional<IUdfpsOverlayController> mUdfpsOverlayController;
+
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@NonNull private final Optional<ISidefpsController> mSidefpsController;
/**
@@ -58,19 +62,32 @@ public final class SensorOverlays {
}
/**
+ * Create an overlay controller for each modality.
+ *
+ * @param udfpsOverlayController under display fps or null if not present on device
+ */
+ public SensorOverlays(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+ mUdfpsOverlayController = Optional.ofNullable(udfpsOverlayController);
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController = Optional.empty();
+ }
+
+ /**
* Show the overlay.
*
* @param sensorId sensor id
* @param reason reason for showing
* @param client client performing operation
*/
- public void show(int sensorId, @BiometricOverlayConstants.ShowReason int reason,
+ public void show(int sensorId, @BiometricRequestConstants.RequestReason int reason,
@NonNull AcquisitionClient<?> client) {
- if (mSidefpsController.isPresent()) {
- try {
- mSidefpsController.get().show(sensorId, reason);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when showing the side-fps overlay", e);
+ if (!sidefpsControllerRefactor()) {
+ if (mSidefpsController.isPresent()) {
+ try {
+ mSidefpsController.get().show(sensorId, reason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when showing the side-fps overlay", e);
+ }
}
}
@@ -98,11 +115,13 @@ public final class SensorOverlays {
* @param sensorId sensor id
*/
public void hide(int sensorId) {
- if (mSidefpsController.isPresent()) {
- try {
- mSidefpsController.get().hide(sensorId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when hiding the side-fps overlay", e);
+ if (!sidefpsControllerRefactor()) {
+ if (mSidefpsController.isPresent()) {
+ try {
+ mSidefpsController.get().hide(sensorId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when hiding the side-fps overlay", e);
+ }
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 5084b602bff2..578d9dc2aede 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -722,6 +722,7 @@ public class FaceService extends SystemService {
if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
if (virtualAt != -1) {
//only virtual instance should be returned
+ Slog.i(TAG, "virtual hal is used");
return new Pair(new ArrayList<>(), List.of(aidlInstances.get(virtualAt)));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 5ce0c8b384ef..83b306b07c27 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -33,6 +33,7 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -81,6 +82,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -128,6 +130,8 @@ public class FingerprintService extends SystemService {
private final BiometricStateCallback<ServiceProvider, FingerprintSensorPropertiesInternal>
mBiometricStateCallback;
@NonNull
+ private final AuthenticationStateListeners mAuthenticationStateListeners;
+ @NonNull
private final Handler mHandler;
@NonNull
private final FingerprintServiceRegistry mRegistry;
@@ -891,6 +895,7 @@ public class FingerprintService extends SystemService {
return providers;
});
}
+
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void addAuthenticatorsRegisteredCallback(
@@ -902,6 +907,24 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
+ public void registerAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ super.registerAuthenticationStateListener_enforcePermission();
+
+ mAuthenticationStateListeners.registerAuthenticationStateListener(listener);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
+ public void unregisterAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ super.unregisterAuthenticationStateListener_enforcePermission();
+
+ mAuthenticationStateListeners.unregisterAuthenticationStateListener(listener);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
super.registerBiometricStateListener_enforcePermission();
@@ -957,6 +980,7 @@ public class FingerprintService extends SystemService {
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
@@ -1014,6 +1038,7 @@ public class FingerprintService extends SystemService {
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
+ mAuthenticationStateListeners = new AuthenticationStateListeners();
mFingerprintProvider = fingerprintProvider != null ? fingerprintProvider :
(name) -> {
final String fqName = IFingerprint.DESCRIPTOR + "/" + name;
@@ -1022,9 +1047,9 @@ public class FingerprintService extends SystemService {
if (fp != null) {
try {
return new FingerprintProvider(getContext(),
- mBiometricStateCallback, fp.getSensorProps(), name,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
- mBiometricContext);
+ mBiometricStateCallback, mAuthenticationStateListeners,
+ fp.getSensorProps(), name, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher, mBiometricContext);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
@@ -1057,6 +1082,7 @@ public class FingerprintService extends SystemService {
if (Utils.isVirtualEnabled(getContext())) {
if (virtualAt != -1) {
//only virtual instance should be returned
+ Slog.i(TAG, "virtual hal is used");
return new Pair(new ArrayList<>(), List.of(aidlInstances.get(virtualAt)));
} else {
Slog.e(TAG, "Could not find virtual interface while it is enabled");
@@ -1085,13 +1111,13 @@ public class FingerprintService extends SystemService {
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
+ mBiometricStateCallback, mAuthenticationStateListeners,
+ hidlSensor, mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
BiometricContext.getInstance(getContext()));
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor, mHandler,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ mBiometricStateCallback, mAuthenticationStateListeners, hidlSensor,
+ mHandler, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
providers.add(fingerprint21);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index a15d1a4df39f..fc37d7020a21 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -135,6 +135,7 @@ public interface ServiceProvider extends
void onPowerPressed();
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* Sets side-fps controller
* @param controller side-fps controller
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 337c3c299e54..29c5a3de3a80 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
@@ -48,6 +50,7 @@ import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -84,6 +87,7 @@ public class FingerprintAuthenticationClient
private final int mSkipWaitForPowerVendorAcquireMessage;
private final long mFingerUpIgnoresPower = 500;
private final AuthSessionCoordinator mAuthSessionCoordinator;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
@Nullable
private ICancellationSignal mCancellationSignal;
private boolean mIsPointerDown;
@@ -110,7 +114,9 @@ public class FingerprintAuthenticationClient
boolean isStrongBiometric,
@Nullable TaskStackListener taskStackListener,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@@ -136,7 +142,12 @@ public class FingerprintAuthenticationClient
false /* shouldVibrate */,
biometricStrength);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
mHandler = handler;
@@ -216,6 +227,9 @@ public class FingerprintAuthenticationClient
if (authenticated) {
mState = STATE_STOPPED;
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
} else {
mState = STATE_STARTED_PAUSED_ATTEMPTED;
}
@@ -241,6 +255,9 @@ public class FingerprintAuthenticationClient
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -266,11 +283,17 @@ public class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getShowOverlayReason(), this);
+ mSensorOverlays.show(getSensorId(), getRequestReason(), this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(getRequestReason());
+ }
try {
mCancellationSignal = doAuthenticate();
@@ -280,6 +303,9 @@ public class FingerprintAuthenticationClient
BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -323,6 +349,9 @@ public class FingerprintAuthenticationClient
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
unsubscribeBiometricContext();
if (mCancellationSignal != null) {
@@ -423,6 +452,9 @@ public class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
@@ -450,6 +482,9 @@ public class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index e2413ee1c016..e58e5ae117b5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -16,10 +16,12 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -66,7 +68,12 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession>
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController*/);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(
+ udfpsOverlayController, null /* sideFpsController */);
+ }
mOptions = options;
}
@@ -93,7 +100,7 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession>
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
+ mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 06550d8b4fce..c0761ed8f32b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -42,6 +44,7 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -65,6 +68,7 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
private final @FingerprintManager.EnrollReason int mEnrollReason;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
@Nullable private ICancellationSignal mCancellationSignal;
private final int mMaxTemplatesPerUser;
private boolean mIsPointerDown;
@@ -80,15 +84,18 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
}
}
- public FingerprintEnrollClient(@NonNull Context context,
- @NonNull Supplier<AidlSession> lazyDaemon, @NonNull IBinder token, long requestId,
+ public FingerprintEnrollClient(
+ @NonNull Context context, @NonNull Supplier<AidlSession> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) {
// UDFPS haptics occur when an image is acquired (instead of when the result is known)
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
@@ -96,7 +103,13 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
logger, biometricContext);
setRequestId(requestId);
mSensorProps = sensorProps;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
+
mMaxTemplatesPerUser = maxTemplatesPerUser;
mALSProbeCallback = getLogger().getAmbientLightProbe(true /* startWithClient */);
@@ -130,7 +143,11 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
if (remaining == 0) {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
+
}
@Override
@@ -159,8 +176,10 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
public void onError(int errorCode, int vendorCode) {
super.onError(errorCode, vendorCode);
-
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
@@ -171,8 +190,12 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason),
+ mSensorOverlays.show(getSensorId(), getRequestReasonFromEnrollReason(mEnrollReason),
this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(
+ getRequestReasonFromEnrollReason(mEnrollReason));
+ }
BiometricNotificationUtils.cancelBadCalibrationNotification(getContext());
try {
@@ -210,6 +233,10 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
+
unsubscribeBiometricContext();
if (mCancellationSignal != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 9985b06833c9..032ab87196f8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -64,6 +64,7 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -108,6 +109,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull
private final BiometricStateCallback mBiometricStateCallback;
@NonNull
+ private final AuthenticationStateListeners mAuthenticationStateListeners;
+ @NonNull
private final String mHalInstanceName;
@NonNull
private final Handler mHandler;
@@ -122,6 +125,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull private final BiometricContext mBiometricContext;
@Nullable private IFingerprint mDaemon;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable private ISidefpsController mSidefpsController;
private AuthSessionCoordinator mAuthSessionCoordinator;
@Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
@@ -157,16 +161,19 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public FingerprintProvider(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
- this(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext, null /* daemon */);
+ this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName,
+ lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext,
+ null /* daemon */);
}
@VisibleForTesting FingerprintProvider(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@@ -174,6 +181,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
IFingerprint daemon) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
+ mAuthenticationStateListeners = authenticationStateListeners;
mHalInstanceName = halInstanceName;
mFingerprintSensors = new SensorList<>(ActivityManager.getService());
mHandler = new Handler(Looper.getMainLooper());
@@ -434,7 +442,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricContext,
mFingerprintSensors.get(sensorId).getSensorProperties(),
mUdfpsOverlayController, mSidefpsController,
- maxTemplatesPerUser, enrollReason);
+ mAuthenticationStateListeners, maxTemplatesPerUser, enrollReason);
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(
mBiometricStateCallback, new ClientMonitorCallback() {
@Override
@@ -498,7 +506,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricContext, isStrongBiometric,
mTaskStackListener,
mUdfpsOverlayController, mSidefpsController,
- allowBackgroundAuthentication,
+ mAuthenticationStateListeners, allowBackgroundAuthentication,
mFingerprintSensors.get(sensorId).getSensorProperties(), mHandler,
Utils.getCurrentStrength(sensorId),
SystemClock.elapsedRealtimeClock(),
@@ -732,6 +740,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
mSidefpsController = controller;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 8bfa560b8031..d3cecd0e34c7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -68,6 +68,7 @@ import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -115,6 +116,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final Context mContext;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
@@ -128,6 +130,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Nullable private IBiometricsFingerprint mDaemon;
@NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable private ISidefpsController mSidefpsController;
@NonNull private final BiometricContext mBiometricContext;
@Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
@@ -330,6 +334,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@VisibleForTesting
Fingerprint21(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler,
@NonNull Handler handler,
@@ -338,6 +343,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull BiometricContext biometricContext) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
+ mAuthenticationStateListeners = authenticationStateListeners;
mBiometricContext = biometricContext;
mSensorProperties = sensorProps;
@@ -378,6 +384,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public static Fingerprint21 newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@@ -388,8 +395,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler, scheduler);
- return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, BiometricContext.getInstance(context));
+ return new Fingerprint21(context, biometricStateCallback, authenticationStateListeners,
+ sensorProps, scheduler, handler, lockoutResetDispatcher, controller,
+ BiometricContext.getInstance(context));
}
@Override
@@ -719,7 +727,10 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mSensorProperties.sensorId,
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
- mBiometricContext, mUdfpsOverlayController, mSidefpsController, enrollReason);
+ mBiometricContext, mUdfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController,
+ mAuthenticationStateListeners, enrollReason);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -761,10 +772,14 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
BiometricsProtoEnums.CLIENT_UNKNOWN,
mAuthenticationStatsCollector),
mBiometricContext, null /* sensorProps */,
- mUdfpsOverlayController, mSidefpsController,
+ mUdfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController,
+ mAuthenticationStateListeners,
mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser),
enrollReason);
+
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -880,6 +895,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mBiometricContext, isStrongBiometric,
mTaskStackListener,
mUdfpsOverlayController, mSidefpsController,
+ mAuthenticationStateListeners,
allowBackgroundAuthentication, mSensorProperties, mHandler,
Utils.getCurrentStrength(mSensorId), null /* clock */, mLockoutTracker);
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
@@ -898,6 +914,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController,
+ mAuthenticationStateListeners,
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
@@ -1123,6 +1140,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mUdfpsOverlayController = controller;
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
mSidefpsController = controller;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index c1a9370b5423..88dae6fcc453 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -41,6 +41,7 @@ import android.util.SparseBooleanArray;
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -248,6 +249,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@@ -259,8 +261,9 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
- return new Fingerprint21UdfpsMock(context, biometricStateCallback, sensorProps, scheduler,
- handler, lockoutResetDispatcher, controller, biometricContext);
+ return new Fingerprint21UdfpsMock(context, biometricStateCallback,
+ authenticationStateListeners, sensorProps, scheduler, handler,
+ lockoutResetDispatcher, controller, biometricContext);
}
private static abstract class FakeFingerRunnable implements Runnable {
@@ -388,14 +391,15 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
private Fingerprint21UdfpsMock(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, biometricContext);
+ super(context, biometricStateCallback, authenticationStateListeners, sensorProps, scheduler,
+ handler, lockoutResetDispatcher, controller, biometricContext);
mScheduler = scheduler;
mScheduler.init(this);
mHandler = handler;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 9966e910d502..4c1d4d6d6d12 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
@@ -40,6 +42,7 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -68,6 +71,7 @@ class FingerprintAuthenticationClient
@NonNull private final SensorOverlays mSensorOverlays;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
@NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private boolean mIsPointerDown;
@@ -81,7 +85,9 @@ class FingerprintAuthenticationClient
@NonNull TaskStackListener taskStackListener,
@NonNull LockoutFrameworkImpl lockoutTracker,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Authenticators.Types int sensorStrength) {
@@ -91,7 +97,12 @@ class FingerprintAuthenticationClient
false /* shouldVibrate */, sensorStrength);
setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
}
@@ -128,6 +139,9 @@ class FingerprintAuthenticationClient
mState = STATE_STOPPED;
resetFailedAttempts(getTargetUserId());
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
} else {
mState = STATE_STARTED_PAUSED_ATTEMPTED;
final @LockoutTracker.LockoutMode int lockoutMode =
@@ -141,6 +155,9 @@ class FingerprintAuthenticationClient
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -156,6 +173,9 @@ class FingerprintAuthenticationClient
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
private void resetFailedAttempts(int userId) {
@@ -205,7 +225,10 @@ class FingerprintAuthenticationClient
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getShowOverlayReason(), this);
+ mSensorOverlays.show(getSensorId(), getRequestReason(), this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(getRequestReason());
+ }
try {
// GroupId was never used. In fact, groupId is always the same as userId.
@@ -215,6 +238,9 @@ class FingerprintAuthenticationClient
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -222,6 +248,9 @@ class FingerprintAuthenticationClient
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
try {
getFreshDaemon().cancel();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 0d7f9f23e0e1..6e029d2268e2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -16,12 +16,14 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
@@ -71,7 +73,12 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController */);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(
+ udfpsOverlayController, null /* sideFpsController */);
+ }
mIsStrongBiometric = isStrongBiometric;
}
@@ -97,7 +104,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
+ mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 382e7e2121f4..26332ff6893c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -34,6 +36,7 @@ import android.util.Slog;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -58,22 +61,31 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@NonNull private final SensorOverlays mSensorOverlays;
private final @FingerprintManager.EnrollReason int mEnrollReason;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private boolean mIsPointerDown;
- FingerprintEnrollClient(@NonNull Context context,
- @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
- long requestId, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ FingerprintEnrollClient(
+ @NonNull Context context, @NonNull Supplier<IBiometricsFingerprint> lazyDaemon,
+ @NonNull IBinder token, long requestId,
+ @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int timeoutSec, int sensorId,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@FingerprintManager.EnrollReason int enrollReason) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, sensorId, true /* shouldVibrate */, biometricLogger,
biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mEnrollReason = enrollReason;
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
@@ -110,8 +122,12 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason),
+ mSensorOverlays.show(getSensorId(), getRequestReasonFromEnrollReason(mEnrollReason),
this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(
+ getRequestReasonFromEnrollReason(mEnrollReason));
+ }
BiometricNotificationUtils.cancelBadCalibrationNotification(getContext());
try {
@@ -122,6 +138,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -129,6 +148,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
try {
getFreshDaemon().cancel();
@@ -149,6 +171,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
if (remaining == 0) {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
}
@@ -170,6 +195,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
super.onError(errorCode, vendorCode);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 1e5e147749a2..df179a9b6d65 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1294,8 +1294,8 @@ public class SyncManager {
if (android.content.pm.Flags.stayStopped()) {
try {
return mPackageManagerInternal.isPackageStopped(packageName, userId);
- } catch (IllegalArgumentException e) {
- Log.d(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Couldn't determine stopped state for unknown package: " + packageName);
}
}
return false;
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index dff14b5fbdd0..6ec6a123a4e7 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -327,7 +327,7 @@ public final class DeviceStateManagerService extends SystemService {
Optional<DeviceState> getOverrideState() {
synchronized (mLock) {
if (mActiveOverride.isPresent()) {
- return getStateLocked(mActiveOverride.get().getRequestedState());
+ return getStateLocked(mActiveOverride.get().getRequestedStateIdentifier());
}
return Optional.empty();
}
@@ -342,7 +342,7 @@ public final class DeviceStateManagerService extends SystemService {
Optional<DeviceState> getOverrideBaseState() {
synchronized (mLock) {
if (mActiveBaseStateOverride.isPresent()) {
- return getStateLocked(mActiveBaseStateOverride.get().getRequestedState());
+ return getStateLocked(mActiveBaseStateOverride.get().getRequestedStateIdentifier());
}
return Optional.empty();
}
@@ -499,6 +499,7 @@ public final class DeviceStateManagerService extends SystemService {
* @return {@code true} if the pending state has changed as a result of this call, {@code false}
* otherwise.
*/
+ @GuardedBy("mLock")
private boolean updatePendingStateLocked() {
if (mPendingState.isPresent()) {
// Have pending state, can not configure a new state until the state is committed.
@@ -507,7 +508,8 @@ public final class DeviceStateManagerService extends SystemService {
final DeviceState stateToConfigure;
if (mActiveOverride.isPresent()) {
- stateToConfigure = getStateLocked(mActiveOverride.get().getRequestedState()).get();
+ stateToConfigure = getStateLocked(
+ mActiveOverride.get().getRequestedStateIdentifier()).get();
} else if (mBaseState.isPresent()
&& isSupportedStateLocked(mBaseState.get().getIdentifier())) {
// Base state could have recently become unsupported after a change in supported states.
@@ -599,7 +601,7 @@ public final class DeviceStateManagerService extends SystemService {
// requested state is committed.
OverrideRequest activeRequest = mActiveOverride.orElse(null);
if (activeRequest != null
- && activeRequest.getRequestedState() == newState.getIdentifier()) {
+ && activeRequest.getRequestedStateIdentifier() == newState.getIdentifier()) {
ProcessRecord processRecord = mProcessRecords.get(activeRequest.getPid());
if (processRecord != null) {
processRecord.notifyRequestActiveAsync(activeRequest.getToken());
@@ -666,21 +668,21 @@ public final class DeviceStateManagerService extends SystemService {
case STATUS_ACTIVE:
mActiveOverride = Optional.of(request);
mDeviceStateNotificationController.showStateActiveNotificationIfNeeded(
- request.getRequestedState(), request.getUid());
+ request.getRequestedStateIdentifier(), request.getUid());
break;
case STATUS_CANCELED:
if (mActiveOverride.isPresent() && mActiveOverride.get() == request) {
mActiveOverride = Optional.empty();
mDeviceStateNotificationController.cancelNotification(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
if ((flags & FLAG_THERMAL_CRITICAL) == FLAG_THERMAL_CRITICAL) {
mDeviceStateNotificationController
.showThermalCriticalNotificationIfNeeded(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
} else if ((flags & FLAG_POWER_SAVE_ENABLED) == FLAG_POWER_SAVE_ENABLED) {
mDeviceStateNotificationController
.showPowerSaveNotificationIfNeeded(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
}
}
break;
@@ -723,7 +725,7 @@ public final class DeviceStateManagerService extends SystemService {
*/
@GuardedBy("mLock")
private void enableBaseStateRequestLocked(OverrideRequest request) {
- setBaseState(request.getRequestedState());
+ setBaseState(request.getRequestedStateIdentifier());
mActiveBaseStateOverride = Optional.of(request);
ProcessRecord processRecord = mProcessRecords.get(request.getPid());
processRecord.notifyRequestActiveAsync(request.getToken());
@@ -762,6 +764,11 @@ public final class DeviceStateManagerService extends SystemService {
synchronized (mLock) {
mProcessRecords.remove(processRecord.mPid);
mOverrideRequestController.handleProcessDied(processRecord.mPid);
+
+ if (shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
+ OverrideRequest request = mActiveOverride.get();
+ mOverrideRequestController.cancelRequest(request);
+ }
}
}
@@ -787,7 +794,7 @@ public final class DeviceStateManagerService extends SystemService {
}
OverrideRequest request = new OverrideRequest(token, callingPid, callingUid,
- state, flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
// If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay
if (!hasControlDeviceStatePermission && mRearDisplayState != null
@@ -848,7 +855,7 @@ public final class DeviceStateManagerService extends SystemService {
}
OverrideRequest request = new OverrideRequest(token, callingPid, callingUid,
- state, flags, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mOverrideRequestController.addBaseStateRequest(request);
}
}
@@ -1318,7 +1325,7 @@ public final class DeviceStateManagerService extends SystemService {
if (mActiveOverride.isEmpty()) {
return false;
}
- int identifier = mActiveOverride.get().getRequestedState();
+ int identifier = mActiveOverride.get().getRequestedStateIdentifier();
DeviceState deviceState = mDeviceStates.get(identifier);
return deviceState.hasFlag(DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
}
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequest.java b/services/core/java/com/android/server/devicestate/OverrideRequest.java
index 74cf184e826e..20485c1ac102 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequest.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequest.java
@@ -17,6 +17,7 @@
package com.android.server.devicestate;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.hardware.devicestate.DeviceStateRequest;
import android.os.IBinder;
@@ -32,7 +33,8 @@ final class OverrideRequest {
private final IBinder mToken;
private final int mPid;
private final int mUid;
- private final int mRequestedState;
+ @NonNull
+ private final DeviceState mRequestedState;
@DeviceStateRequest.RequestFlags
private final int mFlags;
@OverrideRequestType
@@ -69,7 +71,7 @@ final class OverrideRequest {
@Retention(RetentionPolicy.SOURCE)
public @interface OverrideRequestType {}
- OverrideRequest(IBinder token, int pid, int uid, int requestedState,
+ OverrideRequest(IBinder token, int pid, int uid, @NonNull DeviceState requestedState,
@DeviceStateRequest.RequestFlags int flags, @OverrideRequestType int requestType) {
mToken = token;
mPid = pid;
@@ -91,10 +93,15 @@ final class OverrideRequest {
return mUid;
}
- int getRequestedState() {
+ @NonNull
+ DeviceState getRequestedDeviceState() {
return mRequestedState;
}
+ int getRequestedStateIdentifier() {
+ return mRequestedState.getIdentifier();
+ }
+
@DeviceStateRequest.RequestFlags
int getFlags() {
return mFlags;
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequestController.java b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
index 46f0bc0d9805..f5f2fa8cabdc 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequestController.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
@@ -204,6 +204,12 @@ final class OverrideRequestController {
}
if (mRequest != null && mRequest.getPid() == pid) {
+ if (mRequest.getRequestedDeviceState().hasFlag(
+ DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP)) {
+ cancelCurrentRequestLocked();
+ return;
+ }
+
if (mStickyRequestsAllowed) {
// Do not cancel the requests now because sticky requests are allowed. These
// requests will be cancelled on a call to cancelStickyRequests().
@@ -219,7 +225,7 @@ final class OverrideRequestController {
* listener of all changes to request status as a result of this change.
*/
void handleBaseStateChanged(int state) {
- if (mBaseStateRequest != null && state != mBaseStateRequest.getRequestedState()) {
+ if (mBaseStateRequest != null && state != mBaseStateRequest.getRequestedStateIdentifier()) {
cancelBaseStateOverrideRequest();
}
if (mRequest == null) {
@@ -246,11 +252,12 @@ final class OverrideRequestController {
flags |= isThermalCritical ? FLAG_THERMAL_CRITICAL : 0;
flags |= isPowerSaveEnabled ? FLAG_POWER_SAVE_ENABLED : 0;
if (mBaseStateRequest != null && !contains(newSupportedStates,
- mBaseStateRequest.getRequestedState())) {
+ mBaseStateRequest.getRequestedStateIdentifier())) {
cancelCurrentBaseStateRequestLocked(flags);
}
- if (mRequest != null && !contains(newSupportedStates, mRequest.getRequestedState())) {
+ if (mRequest != null && !contains(newSupportedStates,
+ mRequest.getRequestedStateIdentifier())) {
cancelCurrentRequestLocked(flags);
}
}
@@ -262,7 +269,7 @@ final class OverrideRequestController {
pw.println("Override Request active: " + requestActive);
if (requestActive) {
pw.println("Request: mPid=" + overrideRequest.getPid()
- + ", mRequestedState=" + overrideRequest.getRequestedState()
+ + ", mRequestedState=" + overrideRequest.getRequestedStateIdentifier()
+ ", mFlags=" + overrideRequest.getFlags()
+ ", mStatus=" + statusToString(STATUS_ACTIVE));
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 80c3a270efdf..b54289321e89 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -583,8 +583,8 @@ public class AutomaticBrightnessController {
pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
pw.println(" mAmbientLux=" + mAmbientLux);
pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
- pw.println(" mPreThesholdLux=" + mPreThresholdLux);
- pw.println(" mPreThesholdBrightness=" + mPreThresholdBrightness);
+ pw.println(" mPreThresholdLux=" + mPreThresholdLux);
+ pw.println(" mPreThresholdBrightness=" + mPreThresholdBrightness);
pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index bd5e189a5404..aa7f07d24dbf 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -93,6 +93,10 @@ public class DisplayManagerFlags {
Flags.FLAG_ENABLE_EXTERNAL_VSYNC_PROXIMITY_VOTE,
Flags::enableExternalVsyncProximityVote);
+ private final FlagState mVsyncLowPowerVote = new FlagState(
+ Flags.FLAG_ENABLE_VSYNC_LOW_POWER_VOTE,
+ Flags::enableVsyncLowPowerVote);
+
private final FlagState mBrightnessWearBedtimeModeClamperFlagState = new FlagState(
Flags.FLAG_BRIGHTNESS_WEAR_BEDTIME_MODE_CLAMPER,
Flags::brightnessWearBedtimeModeClamper);
@@ -125,7 +129,6 @@ public class DisplayManagerFlags {
return mPowerThrottlingClamperFlagState.isEnabled();
}
-
/**
* Returns whether adaptive tone improvements are enabled
*/
@@ -198,6 +201,10 @@ public class DisplayManagerFlags {
return mVsyncProximityVote.isEnabled();
}
+ public boolean isVsyncLowPowerVoteEnabled() {
+ return mVsyncLowPowerVote.isEnabled();
+ }
+
public boolean isBrightnessWearBedtimeModeClamperEnabled() {
return mBrightnessWearBedtimeModeClamperFlagState.isEnabled();
}
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 7a723a3290a9..04ecbb9e08ad 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -130,6 +130,14 @@ flag {
}
flag {
+ name: "enable_vsync_low_power_vote"
+ namespace: "display_manager"
+ description: "Feature flag for vsync low power vote"
+ bug: "314920284"
+ is_fixed_read_only: true
+}
+
+flag {
name: "brightness_wear_bedtime_mode_clamper"
namespace: "display_manager"
description: "Feature flag for the Wear Bedtime mode brightness clamper"
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index f7b540bc3753..6e503cbd68f3 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -179,7 +179,7 @@ public class DisplayModeDirector {
private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled;
- private final boolean mVsyncProximityVoteEnabled;
+ private final boolean mDvrrSupported;
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
@@ -190,6 +190,8 @@ public class DisplayModeDirector {
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
@NonNull Injector injector,
@NonNull DisplayManagerFlags displayManagerFlags) {
+ mDvrrSupported = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_supportsDvrr);
mIsDisplayResolutionRangeVotingEnabled = displayManagerFlags
.isDisplayResolutionRangeVotingEnabled();
mIsUserPreferredModeVoteEnabled = displayManagerFlags.isUserPreferredModeVoteEnabled();
@@ -199,7 +201,6 @@ public class DisplayModeDirector {
.isDisplaysRefreshRatesSynchronizationEnabled();
mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
- mVsyncProximityVoteEnabled = displayManagerFlags.isVsyncProximityVoteEnabled();
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
mInjector = injector;
@@ -208,7 +209,8 @@ public class DisplayModeDirector {
mAppRequestObserver = new AppRequestObserver();
mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig());
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
- mSettingsObserver = new SettingsObserver(context, handler);
+ mSettingsObserver = new SettingsObserver(context, handler, mDvrrSupported,
+ displayManagerFlags);
mBrightnessObserver = new BrightnessObserver(context, handler, injector);
mDefaultDisplayDeviceConfig = null;
mUdfpsObserver = new UdfpsObserver();
@@ -290,7 +292,7 @@ public class DisplayModeDirector {
List<Display.Mode> availableModes = new ArrayList<>();
availableModes.add(defaultMode);
VoteSummary primarySummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled,
- mVsyncProximityVoteEnabled, mLoggingEnabled, mSupportsFrameRateOverride);
+ mDvrrSupported, mLoggingEnabled, mSupportsFrameRateOverride);
int lowestConsideredPriority = Vote.MIN_PRIORITY;
int highestConsideredPriority = Vote.MAX_PRIORITY;
@@ -330,7 +332,7 @@ public class DisplayModeDirector {
}
VoteSummary appRequestSummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled,
- mVsyncProximityVoteEnabled, mLoggingEnabled, mSupportsFrameRateOverride);
+ mDvrrSupported, mLoggingEnabled, mSupportsFrameRateOverride);
appRequestSummary.applyVotes(votes,
Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF,
@@ -818,13 +820,17 @@ public class DisplayModeDirector {
private final Uri mMatchContentFrameRateSetting =
Settings.Secure.getUriFor(Settings.Secure.MATCH_CONTENT_FRAME_RATE);
+ private final boolean mVsynLowPowerVoteEnabled;
+
private final Context mContext;
private float mDefaultPeakRefreshRate;
private float mDefaultRefreshRate;
- SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
+ SettingsObserver(@NonNull Context context, @NonNull Handler handler, boolean dvrrSupported,
+ DisplayManagerFlags flags) {
super(handler);
mContext = context;
+ mVsynLowPowerVoteEnabled = dvrrSupported && flags.isVsyncLowPowerVoteEnabled();
// We don't want to load from the DeviceConfig while constructing since this leads to
// a spike in the latency of DisplayManagerService startup. This happens because
// reading from the DeviceConfig is an intensive IO operation and having it in the
@@ -936,7 +942,14 @@ public class DisplayModeDirector {
boolean inLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0;
final Vote vote;
- if (inLowPowerMode) {
+ if (inLowPowerMode && mVsynLowPowerVoteEnabled) {
+ vote = Vote.forSupportedModes(List.of(
+ new SupportedModesVote.SupportedMode(/* peakRefreshRate= */ 60f,
+ /* vsyncRate= */ 240f),
+ new SupportedModesVote.SupportedMode(/* peakRefreshRate= */ 60f,
+ /* vsyncRate= */ 60f)
+ ));
+ } else if (inLowPowerMode) {
vote = Vote.forRenderFrameRates(0f, 60f);
} else {
vote = null;
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
index aa44566f6d99..8f3957011b59 100644
--- a/services/core/java/com/android/server/display/mode/Vote.java
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -166,6 +166,10 @@ interface Vote {
return new BaseModeRefreshRateVote(baseModeRefreshRate);
}
+ static Vote forSupportedModes(List<SupportedModesVote.SupportedMode> supportedModes) {
+ return new SupportedModesVote(supportedModes);
+ }
+
static String priorityToString(int priority) {
switch (priority) {
case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
diff --git a/services/core/java/com/android/server/display/mode/VoteSummary.java b/services/core/java/com/android/server/display/mode/VoteSummary.java
index 99f414267dee..5fc36b589d38 100644
--- a/services/core/java/com/android/server/display/mode/VoteSummary.java
+++ b/services/core/java/com/android/server/display/mode/VoteSummary.java
@@ -43,14 +43,14 @@ final class VoteSummary {
final boolean mIsDisplayResolutionRangeVotingEnabled;
- private final boolean mVsyncProximityVoteEnabled;
+ private final boolean mSupportedModesVoteEnabled;
private final boolean mSupportsFrameRateOverride;
private final boolean mLoggingEnabled;
- VoteSummary(boolean isDisplayResolutionRangeVotingEnabled, boolean vsyncProximityVoteEnabled,
+ VoteSummary(boolean isDisplayResolutionRangeVotingEnabled, boolean supportedModesVoteEnabled,
boolean loggingEnabled, boolean supportsFrameRateOverride) {
mIsDisplayResolutionRangeVotingEnabled = isDisplayResolutionRangeVotingEnabled;
- mVsyncProximityVoteEnabled = vsyncProximityVoteEnabled;
+ mSupportedModesVoteEnabled = supportedModesVoteEnabled;
mLoggingEnabled = loggingEnabled;
mSupportsFrameRateOverride = supportsFrameRateOverride;
reset();
@@ -253,7 +253,7 @@ final class VoteSummary {
}
private boolean validateModeSupported(Display.Mode mode) {
- if (supportedModes == null || !mVsyncProximityVoteEnabled) {
+ if (supportedModes == null || !mSupportedModesVoteEnabled) {
return true;
}
for (SupportedModesVote.SupportedMode supportedMode : supportedModes) {
@@ -298,7 +298,7 @@ final class VoteSummary {
return false;
}
- if (supportedModes != null && mVsyncProximityVoteEnabled && supportedModes.isEmpty()) {
+ if (supportedModes != null && mSupportedModesVoteEnabled && supportedModes.isEmpty()) {
if (mLoggingEnabled) {
Slog.w(TAG, "Vote summary resulted in empty set (empty supportedModes)");
}
@@ -370,7 +370,7 @@ final class VoteSummary {
+ ", supportedModes=" + supportedModes
+ ", mIsDisplayResolutionRangeVotingEnabled="
+ mIsDisplayResolutionRangeVotingEnabled
- + ", mVsyncProximityVoteEnabled=" + mVsyncProximityVoteEnabled
+ + ", mSupportedModesVoteEnabled=" + mSupportedModesVoteEnabled
+ ", mSupportsFrameRateOverride=" + mSupportsFrameRateOverride + " }";
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 168715713f8d..5831b29437dc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -194,10 +194,14 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
addAndStartAction(new RequestActiveSourceAction(this, new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) {
- if (result != HdmiControlManager.RESULT_SUCCESS) {
+ if (!mService.getLocalActiveSource().isValid()
+ && result != HdmiControlManager.RESULT_SUCCESS) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
getDeviceInfo().getLogicalAddress(),
getDeviceInfo().getPhysicalAddress()));
+ updateActiveSource(getDeviceInfo().getLogicalAddress(),
+ getDeviceInfo().getPhysicalAddress(),
+ "RequestActiveSourceAction#finishWithCallback()");
}
}
}));
@@ -257,6 +261,7 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (isAlreadyActiveSource(targetDevice, targetAddress, callback)) {
return;
}
+ removeAction(RequestActiveSourceAction.class);
if (targetAddress == Constants.ADDR_INTERNAL) {
handleSelectInternalSource();
// Switching to internal source is always successful even when CEC control is disabled.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index f526dbe9c66d..4089a81dfc20 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -215,10 +215,20 @@ public abstract class InputMethodManagerInternal {
/**
* Switch the keyboard layout in response to a keyboard shortcut.
*
- * @param direction {@code 1} to switch to the next subtype, {@code -1} to switch to the
- * previous subtype
+ * @param direction {@code 1} to switch to the next subtype, {@code -1} to switch to the
+ * previous subtype
+ * @param displayId the display to which the keyboard layout switch shortcut is
+ * dispatched. Note that there is no guarantee that an IME is
+ * associated with this display. This is more or less than a hint for
+ * cases when no IME is running for the given targetWindowToken. There
+ * is a longstanding discussion whether we should allow users to
+ * rotate keyboard layout even when there is no edit field, and this
+ * displayID would be helpful for such a situation.
+ * @param targetWindowToken the window token to which other keys are being sent while handling
+ * this shortcut.
*/
- public abstract void switchKeyboardLayout(int direction);
+ public abstract void onSwitchKeyboardLayoutShortcut(int direction, int displayId,
+ IBinder targetWindowToken);
/**
* Returns true if any InputConnection is currently active.
@@ -314,7 +324,8 @@ public abstract class InputMethodManagerInternal {
}
@Override
- public void switchKeyboardLayout(int direction) {
+ public void onSwitchKeyboardLayoutShortcut(int direction, int displayId,
+ IBinder targetWindowToken) {
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 30e9f5bd2a14..16e043cfb64d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5763,7 +5763,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public void switchKeyboardLayout(int direction) {
+ public void onSwitchKeyboardLayoutShortcut(int direction, int displayId,
+ IBinder targetWindowToken) {
synchronized (ImfLock.class) {
switchKeyboardLayoutLocked(direction);
}
@@ -6498,10 +6499,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
nextEnabledImes).getId();
// Reset enabled IMEs.
- settings.putEnabledInputMethodsStr("");
- nextEnabledImes.forEach(
- imi -> settings.appendAndPutEnabledInputMethodLocked(
- imi.getId()));
+ final String[] nextEnabledImeIds = new String[nextEnabledImes.size()];
+ for (int i = 0; i < nextEnabledImeIds.length; ++i) {
+ nextEnabledImeIds[i] = nextEnabledImes.get(i).getId();
+ }
+ settings.putEnabledInputMethodsStr(InputMethodUtils.concatEnabledImeIds(
+ settings.getEnabledInputMethodsStr(), nextEnabledImeIds));
// Reset selected IME.
settings.putSelectedInputMethod(nextIme);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 2128356e69c6..773293f83323 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -33,6 +33,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
@@ -50,6 +51,8 @@ import com.android.server.textservices.TextServicesManagerInternal;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.StringJoiner;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -952,24 +955,64 @@ final class InputMethodUtils {
final String enabledInputMethodsStr = TextUtils.nullIfEmpty(
SecureSettingsWrapper.getString(Settings.Secure.ENABLED_INPUT_METHODS, null,
userId));
- if (enabledInputMethodsStr == null) {
- return List.of();
+ final ArrayList<String> result = new ArrayList<>();
+ splitEnabledImeStr(enabledInputMethodsStr, result::add);
+ return result;
+ }
+
+ /**
+ * Split enabled IME string ({@link Settings.Secure#ENABLED_INPUT_METHODS}) into IME IDs.
+ *
+ * @param text a text formatted with {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+ * @param consumer {@link Consumer} called back when a new IME ID is found.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ static void splitEnabledImeStr(@Nullable String text, @NonNull Consumer<String> consumer) {
+ if (TextUtils.isEmpty(text)) {
+ return;
}
final TextUtils.SimpleStringSplitter inputMethodSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATOR);
final TextUtils.SimpleStringSplitter subtypeSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR);
- inputMethodSplitter.setString(enabledInputMethodsStr);
- final ArrayList<String> result = new ArrayList<>();
+ inputMethodSplitter.setString(text);
while (inputMethodSplitter.hasNext()) {
String nextImsStr = inputMethodSplitter.next();
subtypeSplitter.setString(nextImsStr);
if (subtypeSplitter.hasNext()) {
// The first element is ime id.
- result.add(subtypeSplitter.next());
+ consumer.accept(subtypeSplitter.next());
}
}
- return result;
+ }
+
+ /**
+ * Concat given IME IDs with an existing enabled IME
+ * ({@link Settings.Secure#ENABLED_INPUT_METHODS}).
+ *
+ * @param existingEnabledImeId an existing {@link Settings.Secure#ENABLED_INPUT_METHODS} to
+ * which {@code imeIDs} will be added.
+ * @param imeIds an array of IME IDs to be added. For IME IDs that are already seen in
+ * {@code existingEnabledImeId} will be skipped.
+ * @return a new enabled IME ID string that can be stored in
+ * {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+ */
+ @NonNull
+ static String concatEnabledImeIds(@NonNull String existingEnabledImeId,
+ @NonNull String... imeIds) {
+ final ArraySet<String> alreadyEnabledIds = new ArraySet<>();
+ final StringJoiner joiner = new StringJoiner(Character.toString(INPUT_METHOD_SEPARATOR));
+ if (!TextUtils.isEmpty(existingEnabledImeId)) {
+ splitEnabledImeStr(existingEnabledImeId, alreadyEnabledIds::add);
+ joiner.add(existingEnabledImeId);
+ }
+ for (String id : imeIds) {
+ if (!alreadyEnabledIds.contains(id)) {
+ joiner.add(id);
+ alreadyEnabledIds.add(id);
+ }
+ }
+ return joiner.toString();
}
/**
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index ec858ee296e1..f2dcba45e312 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -59,6 +59,7 @@ import android.util.apk.SourceStampVerifier;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
@@ -67,7 +68,6 @@ import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index bab3cbea108e..9c27c22dfd00 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -18,6 +18,7 @@ package com.android.server.location.contexthub;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.contexthub.HostEndpointInfo;
+import android.hardware.contexthub.MessageDeliveryStatus;
import android.hardware.contexthub.NanSessionRequest;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
@@ -467,6 +468,11 @@ public abstract class IContextHubWrapper {
// TODO(271471342): Implement
}
+ public void handleMessageDeliveryStatus(char hostEndPointId,
+ MessageDeliveryStatus messageDeliveryStatus) {
+ // TODO(b/312417087): Implement reliable message support
+ }
+
public byte[] getUuid() {
return UUID;
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 42c2548264d4..0c2eee5aebbe 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -209,7 +209,7 @@ import javax.crypto.spec.GCMParameterSpec;
* <li>Protect each user's data using their SP. For example, use the SP to encrypt/decrypt the
* user's credential-encrypted (CE) key for file-based encryption (FBE).</li>
*
- * <li>Generate, protect, and use profile passwords for managed profiles.</li>
+ * <li>Generate, protect, and use unified profile passwords.</li>
*
* <li>Support unlocking the SP by alternative means: resume-on-reboot (reboot escrow) for easier
* OTA updates, and escrow tokens when set up by the Device Policy Controller (DPC).</li>
@@ -287,7 +287,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private final java.security.KeyStore mJavaKeyStore;
private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
- private ManagedProfilePasswordCache mManagedProfilePasswordCache;
+ private final UnifiedProfilePasswordCache mUnifiedProfilePasswordCache;
private final RebootEscrowManager mRebootEscrowManager;
@@ -404,7 +404,8 @@ public class LockSettingsService extends ILockSettings.Stub {
for (int i = 0; i < newPasswordChars.length; i++) {
newPassword[i] = (byte) newPasswordChars[i];
}
- LockscreenCredential credential = LockscreenCredential.createManagedPassword(newPassword);
+ LockscreenCredential credential =
+ LockscreenCredential.createUnifiedProfilePassword(newPassword);
Arrays.fill(newPasswordChars, '\u0000');
Arrays.fill(newPassword, (byte) 0);
Arrays.fill(randomLockSeed, (byte) 0);
@@ -424,7 +425,7 @@ public class LockSettingsService extends ILockSettings.Stub {
if (!isCredentialSharableWithParent(profileUserId)) {
return;
}
- // Do not tie profile when work challenge is enabled
+ // Do not tie profile when separate challenge is enabled
if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
return;
}
@@ -462,7 +463,7 @@ public class LockSettingsService extends ILockSettings.Stub {
setLockCredentialInternal(unifiedProfilePassword, profileUserPassword, profileUserId,
/* isLockTiedToParent= */ true);
tieProfileLockToParent(profileUserId, parent.id, unifiedProfilePassword);
- mManagedProfilePasswordCache.storePassword(profileUserId, unifiedProfilePassword,
+ mUnifiedProfilePasswordCache.storePassword(profileUserId, unifiedProfilePassword,
parentSid);
}
}
@@ -620,9 +621,9 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache(
+ public @NonNull UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(
java.security.KeyStore ks) {
- return new ManagedProfilePasswordCache(ks);
+ return new UnifiedProfilePasswordCache(ks);
}
public boolean isHeadlessSystemUserMode() {
@@ -665,7 +666,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mGatekeeperPasswords = new LongSparseArray<>();
mSpManager = injector.getSyntheticPasswordManager(mStorage);
- mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(mJavaKeyStore);
+ mUnifiedProfilePasswordCache = injector.getUnifiedProfilePasswordCache(mJavaKeyStore);
mBiometricDeferredQueue = new BiometricDeferredQueue(mSpManager, mHandler);
mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
@@ -689,8 +690,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
/**
- * If the account is credential-encrypted, show notification requesting the user to unlock the
- * device.
+ * If the user is a managed profile whose credential-encrypted storage is locked, show a
+ * notification requesting the user to unlock the device.
*/
private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId, String reason) {
final UserInfo user = mUserManager.getUserInfo(userId);
@@ -846,7 +847,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mHandler.post(new Runnable() {
@Override
public void run() {
- // Hide notification first, as tie managed profile lock takes time
+ // Hide notification first, as tie profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
if (isCredentialSharableWithParent(userId)) {
@@ -1458,13 +1459,13 @@ public class LockSettingsService extends ILockSettings.Stub {
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
decryptionResult = cipher.doFinal(encryptedPassword);
- LockscreenCredential credential = LockscreenCredential.createManagedPassword(
+ LockscreenCredential credential = LockscreenCredential.createUnifiedProfilePassword(
decryptionResult);
Arrays.fill(decryptionResult, (byte) 0);
try {
long parentSid = getGateKeeperService().getSecureUserId(
mUserManager.getProfileParent(userId).id);
- mManagedProfilePasswordCache.storePassword(userId, credential, parentSid);
+ mUnifiedProfilePasswordCache.storePassword(userId, credential, parentSid);
} catch (RemoteException e) {
Slogf.w(TAG, "Failed to talk to GateKeeper service", e);
}
@@ -1550,7 +1551,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// so it goes into the cache
getDecryptedPasswordForTiedProfile(profile.id);
} catch (GeneralSecurityException | IOException e) {
- Slog.d(TAG, "Cache work profile password failed", e);
+ Slog.d(TAG, "Cache unified profile password failed", e);
}
}
}
@@ -1604,19 +1605,19 @@ public class LockSettingsService extends ILockSettings.Stub {
}
/**
- * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
+ * Synchronize all profile's challenge of the given user if it's unified: tie or clear them
* depending on the parent user's secure state.
*
- * When clearing tied work challenges, a pre-computed password table for profiles are required,
- * since changing password for profiles requires existing password, and existing passwords can
- * only be computed before the parent user's password is cleared.
+ * When clearing tied challenges, a pre-computed password table for profiles are required, since
+ * changing password for profiles requires existing password, and existing passwords can only be
+ * computed before the parent user's password is cleared.
*
* Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
* method again on profiles. However the recursion is guaranteed to terminate as this method
* terminates when the user is a profile that shares lock credentials with parent.
* (e.g. managed and clone profile).
*/
- private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
+ private void synchronizeUnifiedChallengeForProfiles(int userId,
Map<Integer, LockscreenCredential> profilePasswordMap) {
if (isCredentialSharableWithParent(userId)) {
return;
@@ -1635,7 +1636,7 @@ public class LockSettingsService extends ILockSettings.Stub {
tieProfileLockIfNecessary(profileUserId,
LockscreenCredential.createNone());
} else {
- // We use cached work profile password computed before clearing the parent's
+ // We use cached profile password computed before clearing the parent's
// credential, otherwise they get lost
if (profilePasswordMap != null
&& profilePasswordMap.containsKey(profileUserId)) {
@@ -1777,7 +1778,7 @@ public class LockSettingsService extends ILockSettings.Stub {
notifyPasswordChanged(credential, userId);
}
if (isCredentialSharableWithParent(userId)) {
- // Make sure the profile doesn't get locked straight after setting work challenge.
+ // Make sure the profile doesn't get locked straight after setting challenge.
setDeviceUnlockedForUser(userId);
}
notifySeparateProfileChallengeChanged(userId);
@@ -2368,7 +2369,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
try {
- // Unlock work profile, and work profile with unified lock must use password only
+ // Unlock profile with unified lock
return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
userId, null /* progressCallback */, flags);
} catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
@@ -2492,7 +2493,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mStrongAuth.removeUser(userId);
AndroidKeyStoreMaintenance.onUserRemoved(userId);
- mManagedProfilePasswordCache.removePassword(userId);
+ mUnifiedProfilePasswordCache.removePassword(userId);
gateKeeperClearSecureUserId(userId);
removeKeystoreProfileKey(userId);
@@ -2982,7 +2983,7 @@ public class LockSettingsService extends ILockSettings.Stub {
credential, sp, userId);
final Map<Integer, LockscreenCredential> profilePasswords;
if (!credential.isNone()) {
- // not needed by synchronizeUnifiedWorkChallengeForProfiles()
+ // not needed by synchronizeUnifiedChallengeForProfiles()
profilePasswords = null;
if (!mSpManager.hasSidForUser(userId)) {
@@ -2993,8 +2994,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
} else {
- // Cache all profile password if they use unified work challenge. This will later be
- // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
+ // Cache all profile password if they use unified challenge. This will later be used to
+ // clear the profile's password in synchronizeUnifiedChallengeForProfiles().
profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
mSpManager.clearSidForUser(userId);
@@ -3010,10 +3011,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
setCurrentLskfBasedProtectorId(newProtectorId, userId);
LockPatternUtils.invalidateCredentialTypeCache();
- synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
+ synchronizeUnifiedChallengeForProfiles(userId, profilePasswords);
setUserPasswordMetrics(credential, userId);
- mManagedProfilePasswordCache.removePassword(userId);
+ mUnifiedProfilePasswordCache.removePassword(userId);
if (savedCredentialType != CREDENTIAL_TYPE_NONE) {
mSpManager.destroyAllWeakTokenBasedProtectors(userId);
}
@@ -3114,7 +3115,7 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
currentCredential = getDecryptedPasswordForTiedProfile(userId);
} catch (Exception e) {
- Slog.e(TAG, "Failed to get work profile credential", e);
+ Slog.e(TAG, "Failed to get unified profile password", e);
return null;
}
}
@@ -3284,7 +3285,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public boolean tryUnlockWithCachedUnifiedChallenge(int userId) {
checkPasswordReadPermission();
- try (LockscreenCredential cred = mManagedProfilePasswordCache.retrievePassword(userId)) {
+ try (LockscreenCredential cred = mUnifiedProfilePasswordCache.retrievePassword(userId)) {
if (cred == null) {
return false;
}
@@ -3296,7 +3297,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public void removeCachedUnifiedChallenge(int userId) {
checkWritePermission();
- mManagedProfilePasswordCache.removePassword(userId);
+ mUnifiedProfilePasswordCache.removePassword(userId);
}
static String timestampToString(long timestamp) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 1e8b387fc189..6d123ccebc7c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -501,10 +501,10 @@ class LockSettingsStorage {
final UserInfo parentInfo = um.getProfileParent(userId);
if (parentInfo == null) {
- // This user owns its lock settings files - safe to delete them
+ // Delete files specific to non-profile users.
deleteFile(getRebootEscrowFile(userId));
} else {
- // Managed profile
+ // Delete files specific to profile users.
removeChildProfileLock(userId);
}
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java
index 1298fe8f07a4..21caf76d30d0 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java
@@ -43,30 +43,31 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
/**
- * Caches *unified* work challenge for managed profiles. The cached credential is encrypted using
- * a keystore key auth-bound to the parent user's lockscreen credential, similar to how unified
- * work challenge is normally secured.
- *
- * <p> The cache is filled whenever the managed profile's unified challenge is created or derived
- * (as part of the parent user's credential verification flow). It's removed when the profile is
- * deleted or a (separate) lockscreen credential is explicitly set on the profile. There is also
- * an ADB command to evict the cache "cmd lock_settings remove-cache --user X", to assist
- * development and testing.
-
- * <p> The encrypted credential is stored in-memory only so the cache does not persist across
- * reboots.
+ * An in-memory cache for unified profile passwords. A "unified profile password" is the random
+ * password that the system automatically generates and manages for each profile that uses a unified
+ * challenge and where the parent user has a secure lock screen.
+ * <p>
+ * Each password in this cache is encrypted by a Keystore key that is auth-bound to the parent user.
+ * This is very similar to how the password is protected on-disk, but the in-memory cache uses a
+ * much longer timeout on the keys: 7 days instead of 30 seconds. This enables use cases like
+ * unpausing work apps without requiring authentication as frequently.
+ * <p>
+ * Unified profile passwords are cached when they are created, or when they are decrypted as part of
+ * the parent user's LSKF verification flow. They are removed when the profile is deleted or when a
+ * separate challenge is explicitly set on the profile. There is also an ADB command to evict a
+ * cached password, "locksettings remove-cache --user X", to assist development and testing.
*/
@VisibleForTesting // public visibility is needed for Mockito
-public class ManagedProfilePasswordCache {
+public class UnifiedProfilePasswordCache {
- private static final String TAG = "ManagedProfilePasswordCache";
+ private static final String TAG = "UnifiedProfilePasswordCache";
private static final int KEY_LENGTH = 256;
private static final int CACHE_TIMEOUT_SECONDS = (int) TimeUnit.DAYS.toSeconds(7);
private final SparseArray<byte[]> mEncryptedPasswords = new SparseArray<>();
private final KeyStore mKeyStore;
- public ManagedProfilePasswordCache(KeyStore keyStore) {
+ public UnifiedProfilePasswordCache(KeyStore keyStore) {
mKeyStore = keyStore;
}
@@ -151,7 +152,8 @@ public class ManagedProfilePasswordCache {
Slog.d(TAG, "Cannot decrypt", e);
return null;
}
- LockscreenCredential result = LockscreenCredential.createManagedPassword(credential);
+ LockscreenCredential result =
+ LockscreenCredential.createUnifiedProfilePassword(credential);
Arrays.fill(credential, (byte) 0);
return result;
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 10b6052bec69..e5807e84a70e 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -82,6 +82,7 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -272,9 +273,10 @@ public class RecoverableKeyStoreManager {
CertPath certPath;
X509Certificate rootCert =
mTestCertHelper.getRootCertificate(rootCertificateAlias);
+ Date validationDate = mTestCertHelper.getValidationDate(rootCertificateAlias);
try {
Log.d(TAG, "Getting and validating a random endpoint certificate");
- certPath = certXml.getRandomEndpointCert(rootCert);
+ certPath = certXml.getRandomEndpointCert(rootCert, validationDate);
} catch (CertValidationException e) {
Log.e(TAG, "Invalid endpoint cert", e);
throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE, e.getMessage());
@@ -348,10 +350,11 @@ public class RecoverableKeyStoreManager {
X509Certificate rootCert =
mTestCertHelper.getRootCertificate(rootCertificateAlias);
+ Date validationDate = mTestCertHelper.getValidationDate(rootCertificateAlias);
try {
- sigXml.verifyFileSignature(rootCert, recoveryServiceCertFile);
+ sigXml.verifyFileSignature(rootCert, recoveryServiceCertFile, validationDate);
} catch (CertValidationException e) {
- Log.d(TAG, "The signature over the cert file is invalid."
+ Log.e(TAG, "The signature over the cert file is invalid."
+ " Cert: " + HexDump.toHexString(recoveryServiceCertFile)
+ " Sig: " + HexDump.toHexString(recoveryServiceSigFile));
throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE, e.getMessage());
@@ -601,8 +604,9 @@ public class RecoverableKeyStoreManager {
}
try {
- CertUtils.validateCertPath(
- mTestCertHelper.getRootCertificate(rootCertificateAlias), certPath);
+ Date validationDate = mTestCertHelper.getValidationDate(rootCertificateAlias);
+ CertUtils.validateCertPath(mTestCertHelper.getRootCertificate(rootCertificateAlias),
+ certPath, validationDate);
} catch (CertValidationException e) {
Log.e(TAG, "Failed to validate the given cert path", e);
throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE, e.getMessage());
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
index c963f799245f..4a1cae2037f9 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
@@ -29,6 +29,7 @@ import android.util.Pair;
import com.android.internal.widget.LockPatternUtils;
import java.security.cert.X509Certificate;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -67,6 +68,18 @@ public class TestOnlyInsecureCertificateHelper {
return rootCertificate;
}
+ /**
+ * Returns hardcoded validation date for e2e tests.
+ */
+ public @Nullable Date getValidationDate(String rootCertificateAlias) {
+ if (isTestOnlyCertificateAlias(rootCertificateAlias)) {
+ // Certificate used for e2e test is expired.
+ return new Date(2019 - 1900, 1, 30);
+ } else {
+ return null; // Use current time
+ }
+ }
+
public @NonNull String getDefaultCertificateAliasIfEmpty(
@Nullable String rootCertificateAlias) {
if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
index 26e82704b357..088127526d18 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
@@ -305,12 +305,13 @@ public final class CertUtils {
*
* @param trustedRoot the trusted root certificate
* @param certPath the certificate path to be validated
+ * @param validationDate use null for current time
* @throws CertValidationException if the given certificate path is invalid, e.g., is expired,
* or does not have a valid signature
*/
- public static void validateCertPath(X509Certificate trustedRoot, CertPath certPath)
- throws CertValidationException {
- validateCertPath(/*validationDate=*/ null, trustedRoot, certPath);
+ public static void validateCertPath(X509Certificate trustedRoot, CertPath certPath,
+ @Nullable Date validationDate) throws CertValidationException {
+ validateCertPath(validationDate, trustedRoot, certPath);
}
/**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
index ff22a8dc934f..d159a84f0468 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
@@ -76,15 +76,16 @@ public final class CertXml {
* and returns the certificate path including the chosen certificate if it is valid.
*
* @param trustedRoot the trusted root certificate
+ * @param validationDate use null for current time
* @return the certificate path including the chosen certificate if the certificate is valid
* @throws CertValidationException if the chosen certificate cannot be validated based on the
* trusted root certificate
*/
- public CertPath getRandomEndpointCert(X509Certificate trustedRoot)
- throws CertValidationException {
+ public CertPath getRandomEndpointCert(X509Certificate trustedRoot,
+ @Nullable Date validationDate)throws CertValidationException {
return getEndpointCert(
new SecureRandom().nextInt(this.endpointCerts.size()),
- /*validationDate=*/ null,
+ validationDate,
trustedRoot);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java
index e75be8574254..c3f4f55b2dd7 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java
@@ -18,7 +18,7 @@ package com.android.server.locksettings.recoverablekeystore.certificate;
import android.annotation.Nullable;
-import com.android.internal.annotations.VisibleForTesting;
+import org.w3c.dom.Element;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -26,8 +26,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
-import org.w3c.dom.Element;
-
/**
* Parses and holds the XML file containing the signature of the XML file containing the list of THM
* public-key certificates.
@@ -58,17 +56,13 @@ public final class SigXml {
*
* @param trustedRoot the trusted root certificate
* @param signedFileBytes the original file content that has been signed
+ * @param validationDate use null for current time
+ *
* @throws CertValidationException if the signature verification fails, or the signer's
* certificate contained in this XML file cannot be validated
* based on the trusted root certificate
*/
- public void verifyFileSignature(X509Certificate trustedRoot, byte[] signedFileBytes)
- throws CertValidationException {
- verifyFileSignature(trustedRoot, signedFileBytes, /*validationDate=*/ null);
- }
-
- @VisibleForTesting
- void verifyFileSignature(
+ public void verifyFileSignature(
X509Certificate trustedRoot, byte[] signedFileBytes, @Nullable Date validationDate)
throws CertValidationException {
CertUtils.validateCert(validationDate, trustedRoot, intermediateCerts, signerCert);
diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
index 173c452fd8cb..850449595d74 100644
--- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
+++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
@@ -330,8 +330,11 @@ import java.util.Objects;
TextUtils.isEmpty(address)
? null
: mBluetoothRouteController.getRouteIdForBluetoothAddress(address);
- return createMediaRoute2Info(
- routeId, audioDeviceInfo.getType(), audioDeviceInfo.getProductName(), address);
+ // We use the name from the port instead AudioDeviceInfo#getProductName because the latter
+ // replaces empty names with the name of the device (example: Pixel 8). In that case we want
+ // to derive a name ourselves from the type instead.
+ String deviceName = audioDeviceInfo.getPort().name();
+ return createMediaRoute2Info(routeId, audioDeviceInfo.getType(), deviceName, address);
}
/**
@@ -339,8 +342,8 @@ import java.util.Objects;
*
* @param routeId A route id, or null to use an id pre-defined for the given {@code type}.
* @param audioDeviceInfoType The type as obtained from {@link AudioDeviceInfo#getType}.
- * @param productName The product name as obtained from {@link
- * AudioDeviceInfo#getProductName()}, or null to use a predefined name for the given {@code
+ * @param deviceName A human readable name to populate the route's {@link
+ * MediaRoute2Info#getName name}, or null to use a predefined name for the given {@code
* type}.
* @param address The type as obtained from {@link AudioDeviceInfo#getAddress()} or {@link
* BluetoothDevice#getAddress()}.
@@ -350,7 +353,7 @@ import java.util.Objects;
private MediaRoute2Info createMediaRoute2Info(
@Nullable String routeId,
int audioDeviceInfoType,
- @Nullable CharSequence productName,
+ @Nullable CharSequence deviceName,
@Nullable String address) {
SystemRouteInfo systemRouteInfo =
AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.get(audioDeviceInfoType);
@@ -359,7 +362,7 @@ import java.util.Objects;
// earpiece.
return null;
}
- CharSequence humanReadableName = productName;
+ CharSequence humanReadableName = deviceName;
if (TextUtils.isEmpty(humanReadableName)) {
humanReadableName = mContext.getResources().getText(systemRouteInfo.mNameResource);
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index df9e7417054b..5e18727459c6 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -964,6 +964,7 @@ class MediaRouter2ServiceImpl {
disposeUserIfNeededLocked(userRecord); // since router removed from user
}
+ @GuardedBy("mLock")
private void setDiscoveryRequestWithRouter2Locked(@NonNull RouterRecord routerRecord,
@NonNull RouteDiscoveryPreference discoveryRequest) {
if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
@@ -1016,6 +1017,7 @@ class MediaRouter2ServiceImpl {
routeListingPreference));
}
+ @GuardedBy("mLock")
private void setRouteVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull MediaRoute2Info route, int volume) {
final IBinder binder = router.asBinder();
@@ -1035,6 +1037,7 @@ class MediaRouter2ServiceImpl {
}
}
+ @GuardedBy("mLock")
private void requestCreateSessionWithRouter2Locked(int requestId, long managerRequestId,
@NonNull IMediaRouter2 router, @NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
@@ -1117,6 +1120,7 @@ class MediaRouter2ServiceImpl {
sessionHints));
}
+ @GuardedBy("mLock")
private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1138,6 +1142,7 @@ class MediaRouter2ServiceImpl {
DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1159,6 +1164,7 @@ class MediaRouter2ServiceImpl {
DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1191,6 +1197,7 @@ class MediaRouter2ServiceImpl {
}
}
+ @GuardedBy("mLock")
private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, int volume) {
final IBinder binder = router.asBinder();
@@ -1215,6 +1222,7 @@ class MediaRouter2ServiceImpl {
DUMMY_REQUEST_ID, uniqueSessionId, volume));
}
+ @GuardedBy("mLock")
private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId) {
final IBinder binder = router.asBinder();
@@ -1240,6 +1248,7 @@ class MediaRouter2ServiceImpl {
// Start of locked methods that are used by MediaRouter2Manager.
+ @GuardedBy("mLock")
private List<RoutingSessionInfo> getRemoteSessionsLocked(
@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
@@ -1330,6 +1339,7 @@ class MediaRouter2ServiceImpl {
UserHandler::notifyInitialRoutesToManager, userRecord.mHandler, manager));
}
+ @GuardedBy("mLock")
private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) {
ManagerRecord managerRecord = mAllManagerRecords.remove(manager.asBinder());
if (managerRecord == null) {
@@ -1355,6 +1365,7 @@ class MediaRouter2ServiceImpl {
disposeUserIfNeededLocked(userRecord); // since manager removed from user
}
+ @GuardedBy("mLock")
private void startScanLocked(@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1368,6 +1379,7 @@ class MediaRouter2ServiceImpl {
managerRecord.startScan();
}
+ @GuardedBy("mLock")
private void stopScanLocked(@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1381,6 +1393,7 @@ class MediaRouter2ServiceImpl {
managerRecord.stopScan();
}
+ @GuardedBy("mLock")
private void setRouteVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull MediaRoute2Info route, int volume) {
@@ -1402,6 +1415,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, route, volume));
}
+ @GuardedBy("mLock")
private void requestCreateSessionWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager, @NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route) {
@@ -1455,6 +1469,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, managerRecord, oldSession, route));
}
+ @GuardedBy("mLock")
private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = manager.asBinder();
@@ -1479,6 +1494,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void deselectRouteWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
@@ -1504,6 +1520,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void transferToRouteWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
@@ -1529,6 +1546,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void setSessionVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, int volume) {
@@ -1550,6 +1568,7 @@ class MediaRouter2ServiceImpl {
uniqueRequestId, uniqueSessionId, volume));
}
+ @GuardedBy("mLock")
private void releaseSessionWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager, @NonNull String uniqueSessionId) {
final IBinder binder = manager.asBinder();
@@ -1652,6 +1671,7 @@ class MediaRouter2ServiceImpl {
// TODO: This assumes that only one router exists in a package.
// Do this in Android S or later.
+ @GuardedBy("mLock")
RouterRecord findRouterRecordLocked(String packageName) {
for (RouterRecord routerRecord : mRouterRecords) {
if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
@@ -1739,6 +1759,7 @@ class MediaRouter2ServiceImpl {
return mHasModifyAudioRoutingPermission || mHasBluetoothRoutingPermission.get();
}
+ @GuardedBy("mLock")
public void maybeUpdateSystemRoutingPermissionLocked() {
boolean oldSystemRoutingPermissionValue = hasSystemRoutingPermission();
mHasBluetoothRoutingPermission.set(checkCallerHasBluetoothPermissions(mPid, mUid));
@@ -2063,6 +2084,7 @@ class MediaRouter2ServiceImpl {
this, provider, uniqueRequestId, reason));
}
+ @GuardedBy("mLock")
@Nullable
public RouterRecord findRouterWithSessionLocked(@NonNull String uniqueSessionId) {
return mSessionToRouterMap.get(uniqueSessionId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index b12180bffdcd..4b8de4e8c6f1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -19,6 +19,7 @@ package com.android.server.notification;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import android.service.notification.DeviceEffectsApplier;
import java.util.Set;
@@ -54,4 +55,22 @@ public interface NotificationManagerInternal {
void cleanupHistoryFiles();
void removeBitmaps();
+
+ /**
+ * Sets the {@link DeviceEffectsApplier} that will be used to apply the different
+ * {@link android.service.notification.ZenDeviceEffects} that are relevant for the platform
+ * when {@link android.service.notification.ZenModeConfig.ZenRule} instances are activated and
+ * deactivated.
+ *
+ * <p>This method is optional and needs only be called if the platform supports non-standard
+ * effects (i.e. any that are not <em>public APIs</em> in
+ * {@link android.service.notification.ZenDeviceEffects}, or if they must be applied in a
+ * non-standard fashion. If not used, a {@link DefaultDeviceEffectsApplier} will be invoked,
+ * which should be sufficient for most devices.
+ *
+ * <p>If this method is called, it <em>must</em> be during system startup and <em>before</em>
+ * the {@link com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START} boot phase.
+ * Otherwise an {@link IllegalStateException} will be thrown.
+ */
+ void setDeviceEffectsApplier(DeviceEffectsApplier applier);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c2a145df4114..e7ae61072db4 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -119,6 +119,7 @@ import static android.service.notification.NotificationListenerService.Ranking.R
import static android.service.notification.NotificationListenerService.Ranking.RANKING_UNCHANGED;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
+import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
@@ -250,6 +251,7 @@ import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
import android.service.notification.ConversationChannelWrapper;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
@@ -414,6 +416,12 @@ public class NotificationManagerService extends SystemService {
static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
+ /**
+ * The threshold, in milliseconds, to determine whether a notification has been
+ * cleared too quickly.
+ */
+ private static final int NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS = 5000;
+
static final int INVALID_UID = -1;
static final String ROOT_PKG = "root";
@@ -4817,9 +4825,12 @@ public class NotificationManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final long identity = Binder.clearCallingIdentity();
+ boolean notificationsRapidlyCleared = false;
+ final String pkg;
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ pkg = info.component.getPackageName();
// Cancellation reason. If the token comes from assistant, label the
// cancellation as coming from the assistant; default to LISTENER_CANCEL.
@@ -4838,11 +4849,19 @@ public class NotificationManagerService extends SystemService {
!mUserProfiles.isCurrentProfile(userId)) {
continue;
}
+ notificationsRapidlyCleared = notificationsRapidlyCleared
+ || isNotificationRecent(r);
cancelNotificationFromListenerLocked(info, callingUid, callingPid,
r.getSbn().getPackageName(), r.getSbn().getTag(),
r.getSbn().getId(), userId, reason);
}
} else {
+ for (NotificationRecord notificationRecord : mNotificationList) {
+ if (isNotificationRecent(notificationRecord)) {
+ notificationsRapidlyCleared = true;
+ break;
+ }
+ }
if (lifetimeExtensionRefactor()) {
cancelAllLocked(callingUid, callingPid, info.userid,
REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles(),
@@ -4855,11 +4874,23 @@ public class NotificationManagerService extends SystemService {
}
}
}
+ if (notificationsRapidlyCleared) {
+ mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
+ callingUid, pkg, /* attributionTag= */ null, /* message= */ null);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ private boolean isNotificationRecent(@NonNull NotificationRecord notificationRecord) {
+ if (!rapidClearNotificationsByListenerAppOpEnabled()) {
+ return false;
+ }
+ return notificationRecord.getFreshnessMs(System.currentTimeMillis())
+ < NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS;
+ }
+
/**
* Handle request from an approved listener to re-enable itself.
*
@@ -5334,14 +5365,7 @@ public class NotificationManagerService extends SystemService {
@Override
public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg) {
- Objects.requireNonNull(automaticZenRule, "automaticZenRule is null");
- Objects.requireNonNull(automaticZenRule.getName(), "Name is null");
- if (automaticZenRule.getOwner() == null
- && automaticZenRule.getConfigurationActivity() == null) {
- throw new NullPointerException(
- "Rule must have a conditionproviderservice and/or configuration activity");
- }
- Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null");
+ validateAutomaticZenRule(automaticZenRule);
checkCallerIsSameApp(pkg);
if (automaticZenRule.getZenPolicy() != null
&& automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
@@ -5368,16 +5392,8 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
- throws RemoteException {
- Objects.requireNonNull(automaticZenRule, "automaticZenRule is null");
- Objects.requireNonNull(automaticZenRule.getName(), "Name is null");
- if (automaticZenRule.getOwner() == null
- && automaticZenRule.getConfigurationActivity() == null) {
- throw new NullPointerException(
- "Rule must have a conditionproviderservice and/or configuration activity");
- }
- Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null");
+ public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) {
+ validateAutomaticZenRule(automaticZenRule);
enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
// TODO: b/308670715: Distinguish origin properly (e.g. USER if updating a rule
@@ -5388,6 +5404,30 @@ public class NotificationManagerService extends SystemService {
"updateAutomaticZenRule", Binder.getCallingUid());
}
+ private void validateAutomaticZenRule(AutomaticZenRule rule) {
+ Objects.requireNonNull(rule, "automaticZenRule is null");
+ Objects.requireNonNull(rule.getName(), "Name is null");
+ rule.validate();
+ if (rule.getOwner() == null
+ && rule.getConfigurationActivity() == null) {
+ throw new NullPointerException(
+ "Rule must have a conditionproviderservice and/or configuration activity");
+ }
+ Objects.requireNonNull(rule.getConditionId(), "ConditionId is null");
+
+ if (android.app.Flags.modesApi()) {
+ if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) {
+ int uid = Binder.getCallingUid();
+ boolean isDeviceOwner = Binder.withCleanCallingIdentity(
+ () -> mDpm.isActiveDeviceOwner(uid));
+ if (!isDeviceOwner) {
+ throw new IllegalArgumentException(
+ "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED");
+ }
+ }
+ }
+ }
+
@Override
public boolean removeAutomaticZenRule(String id) throws RemoteException {
Objects.requireNonNull(id, "Id is null");
@@ -5425,6 +5465,7 @@ public class NotificationManagerService extends SystemService {
public void setAutomaticZenRuleState(String id, Condition condition) {
Objects.requireNonNull(id, "id is null");
Objects.requireNonNull(condition, "Condition is null");
+ condition.validate();
enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
@@ -6924,6 +6965,18 @@ public class NotificationManagerService extends SystemService {
}
}
}
+
+ @Override
+ public void setDeviceEffectsApplier(DeviceEffectsApplier applier) {
+ if (!android.app.Flags.modesApi()) {
+ return;
+ }
+ if (mZenModeHelper == null) {
+ throw new IllegalStateException("ZenModeHelper is not yet ready!");
+ }
+ // This can also throw IllegalStateException if called too late.
+ mZenModeHelper.setDeviceEffectsApplier(applier);
+ }
};
private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 7ec94c315798..3f8b5952a1bc 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -627,6 +627,7 @@ public class ZenModeHelper {
try {
ApplicationInfo applicationInfo = mPm.getApplicationInfo(pkg, 0);
rule.name = applicationInfo.loadLabel(mPm).toString();
+ rule.iconResName = drawableResIdToResName(pkg, applicationInfo.icon);
} catch (PackageManager.NameNotFoundException e) {
// Should not happen, since it's the app calling us (?)
Log.w(TAG, "Package not found for creating implicit zen rule");
@@ -634,6 +635,9 @@ public class ZenModeHelper {
}
});
+ rule.type = AutomaticZenRule.TYPE_OTHER;
+ rule.triggerDescription = mContext.getString(R.string.zen_mode_implicit_trigger_description,
+ rule.name);
rule.condition = null;
rule.conditionId = new Uri.Builder()
.scheme(Condition.SCHEME)
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index dcac8c98d19f..da017453ed8b 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -20,3 +20,17 @@ flag {
description: "This flag controls the refactoring of NMS to NotificationAttentionHelper"
bug: "291907312"
}
+
+flag {
+ name: "cross_app_polite_notifications"
+ namespace: "systemui"
+ description: "This flag controls the cross-app effect of polite notifications"
+ bug: "270456865"
+}
+
+flag {
+ name: "vibrate_while_unlocked"
+ namespace: "systemui"
+ description: "This flag controls the vibrate while unlocked setting of polite notifications"
+ bug: "270456865"
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index f985b5b64e21..b9b09fb0e84c 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -754,9 +754,9 @@ public class PersistentDataBlockService extends SystemService {
}
};
- private PersistentDataBlockManagerInternal mInternalService =
- new PersistentDataBlockManagerInternal() {
+ private InternalService mInternalService = new InternalService();
+ private class InternalService implements PersistentDataBlockManagerInternal {
@Override
public void setFrpCredentialHandle(byte[] handle) {
writeInternal(handle, getFrpCredentialDataOffset(), MAX_FRP_CREDENTIAL_HANDLE_SIZE);
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 7b35589ae682..7f58e75e0287 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -837,13 +837,11 @@ public final class BroadcastHelper {
}
final String removedPackage = packageRemovedInfo.mRemovedPackage;
- final int removedAppId = packageRemovedInfo.mRemovedAppId;
- final int uid = packageRemovedInfo.mUid;
final String installerPackageName = packageRemovedInfo.mInstallerPackageName;
final SparseArray<int[]> broadcastAllowList = packageRemovedInfo.mBroadcastAllowList;
Bundle extras = new Bundle(2);
- extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
+ extras.putInt(Intent.EXTRA_UID, packageRemovedInfo.mUid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
sendPackageBroadcastAndNotify(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras,
0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
@@ -888,8 +886,6 @@ public final class BroadcastHelper {
boolean removedBySystem,
boolean isArchived) {
final String removedPackage = packageRemovedInfo.mRemovedPackage;
- final int removedAppId = packageRemovedInfo.mRemovedAppId;
- final int uid = packageRemovedInfo.mUid;
final String installerPackageName = packageRemovedInfo.mInstallerPackageName;
final int[] broadcastUserIds = packageRemovedInfo.mBroadcastUsers;
final int[] instantUserIds = packageRemovedInfo.mInstantUserIds;
@@ -902,8 +898,7 @@ public final class BroadcastHelper {
final boolean isStaticSharedLib = packageRemovedInfo.mIsStaticSharedLib;
Bundle extras = new Bundle();
- final int removedUid = removedAppId >= 0 ? removedAppId : uid;
- extras.putInt(Intent.EXTRA_UID, removedUid);
+ extras.putInt(Intent.EXTRA_UID, packageRemovedInfo.mUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
extras.putBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, isRemovedPackageSystemUpdate);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
@@ -940,10 +935,10 @@ public final class BroadcastHelper {
sendPackageBroadcastAndNotify(Intent.ACTION_PACKAGE_FULLY_REMOVED,
removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
null, broadcastUserIds, instantUserIds, broadcastAllowList, null);
- packageSender.notifyPackageRemoved(removedPackage, removedUid);
+ packageSender.notifyPackageRemoved(removedPackage, packageRemovedInfo.mUid);
}
}
- if (removedAppId >= 0) {
+ if (packageRemovedInfo.mIsAppIdRemoved) {
// If a system app's updates are uninstalled the UID is not actually removed. Some
// services need to know the package name affected.
if (isReplace) {
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index bd725ed49f3c..482807c397ea 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -508,14 +508,19 @@ public interface Computer extends PackageDataSnapshot {
boolean getApplicationHiddenSettingAsUser(@NonNull String packageName, @UserIdInt int userId);
- boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId);
+ boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
- boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId);
+ boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
/** Check if the package is in a stopped state for a given user. */
- boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId);
+ boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException;
- boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
+ /** Check if the package is suspending any package. */
+ boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
+ @UserIdInt int suspendingUserId, int targetUserId);
@NonNull
ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 2dc3fb7464fd..3cb2420cd223 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -96,6 +96,7 @@ import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.VersionedPackage;
import android.os.Binder;
import android.os.Build;
@@ -3864,19 +3865,15 @@ public class ComputerEngine implements Computer {
} finally {
Binder.restoreCallingIdentity(identity);
}
-
- var usingSharedLibraryPair =
- getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
libInfo.getPackageName(), libInfo.getAllCodePaths(),
libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), declaringPackage,
- usingSharedLibraryPair.first,
(libInfo.getDependencies() == null
? null
: new ArrayList<>(libInfo.getDependencies())),
- libInfo.isNative());
-
+ libInfo.isNative(),
+ getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId));
if (result == null) {
result = new ArrayList<>();
}
@@ -4980,40 +4977,45 @@ public class ComputerEngine implements Computer {
}
}
- private PackageUserStateInternal getUserStageOrDefaultForUser(@NonNull String packageName,
- int userId) {
+ private PackageUserStateInternal getUserStateOrDefaultForUser(@NonNull String packageName,
+ int userId) throws PackageManager.NameNotFoundException {
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "when asking about packages for user " + userId);
final PackageStateInternal ps = mSettings.getPackage(packageName);
if (ps == null || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
- throw new IllegalArgumentException("Unknown target package: " + packageName);
+ throw new PackageManager.NameNotFoundException(packageName);
}
return ps.getUserStateOrDefault(userId);
}
@Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, int userId) {
- return getUserStageOrDefaultForUser(packageName, userId).isSuspended();
+ public boolean isPackageSuspendedForUser(@NonNull String packageName, int userId)
+ throws PackageManager.NameNotFoundException {
+ return getUserStateOrDefaultForUser(packageName, userId).isSuspended();
}
@Override
- public boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId) {
- return getUserStageOrDefaultForUser(packageName, userId).isQuarantined();
+ public boolean isPackageQuarantinedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
+ return getUserStateOrDefaultForUser(packageName, userId).isQuarantined();
}
@Override
- public boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId) {
- return getUserStageOrDefaultForUser(packageName, userId).isStopped();
+ public boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
+ return getUserStateOrDefaultForUser(packageName, userId).isStopped();
}
@Override
public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int userId) {
+ @UserIdInt int suspendingUserId, int targetUserId) {
+ final UserPackage suspender = UserPackage.of(suspendingUserId, suspendingPackage);
for (final PackageStateInternal packageState : getPackageStates().values()) {
- final PackageUserStateInternal state = packageState.getUserStateOrDefault(userId);
+ final PackageUserStateInternal state =
+ packageState.getUserStateOrDefault(targetUserId);
if (state.getSuspendParams() != null
- && state.getSuspendParams().containsKey(suspendingPackage)) {
+ && state.getSuspendParams().containsKey(suspender)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/DeletePackageAction.java b/services/core/java/com/android/server/pm/DeletePackageAction.java
index 8ef6601f7684..31544d5308fb 100644
--- a/services/core/java/com/android/server/pm/DeletePackageAction.java
+++ b/services/core/java/com/android/server/pm/DeletePackageAction.java
@@ -16,17 +16,19 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.os.UserHandle;
final class DeletePackageAction {
public final PackageSetting mDeletingPs;
public final PackageSetting mDisabledPs;
+ @NonNull
public final PackageRemovedInfo mRemovedInfo;
public final int mFlags;
public final UserHandle mUser;
DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
- PackageRemovedInfo removedInfo, int flags, UserHandle user) {
+ @NonNull PackageRemovedInfo removedInfo, int flags, UserHandle user) {
mDeletingPs = deletingPs;
mDisabledPs = disabledPs;
mRemovedInfo = removedInfo;
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 93836266d1f4..aa7f0d3c668a 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -370,7 +370,7 @@ final class DeletePackageHelper {
@GuardedBy("mPm.mInstallLock")
public boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags,
- PackageRemovedInfo outInfo, boolean writeSettings) {
+ @NonNull PackageRemovedInfo outInfo, boolean writeSettings) {
final DeletePackageAction action;
synchronized (mPm.mLock) {
final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
@@ -410,8 +410,8 @@ final class DeletePackageHelper {
* deleted, {@code null} otherwise.
*/
@Nullable
- public static DeletePackageAction mayDeletePackageLocked(
- PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
+ public static DeletePackageAction mayDeletePackageLocked(@NonNull PackageRemovedInfo outInfo,
+ PackageSetting ps, @Nullable PackageSetting disabledPs,
int flags, UserHandle user) {
if (ps == null) {
return null;
@@ -460,12 +460,18 @@ final class DeletePackageHelper {
}
final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
- if (outInfo != null) {
- // Remember which users are affected, before the installed states are modified
- outInfo.mRemovedUsers = (systemApp || userId == UserHandle.USER_ALL)
- ? ps.queryUsersInstalledOrHasData(allUserHandles)
- : new int[]{userId};
- }
+ // Remember which users are affected, before the installed states are modified
+ outInfo.mRemovedUsers = (systemApp || userId == UserHandle.USER_ALL)
+ ? ps.queryUsersInstalledOrHasData(allUserHandles)
+ : new int[]{userId};
+ outInfo.populateBroadcastUsers(ps);
+ outInfo.mDataRemoved = (flags & PackageManager.DELETE_KEEP_DATA) == 0;
+ outInfo.mRemovedPackage = ps.getPackageName();
+ outInfo.mInstallerPackageName = ps.getInstallSource().mInstallerPackageName;
+ outInfo.mIsStaticSharedLib =
+ ps.getPkg() != null && ps.getPkg().getStaticSharedLibraryName() != null;
+ outInfo.mIsExternal = ps.isExternalStorage();
+ outInfo.mRemovedPackageVersionCode = ps.getVersionCode();
if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
&& userId != UserHandle.USER_ALL) {
@@ -503,7 +509,11 @@ final class DeletePackageHelper {
}
}
if (clearPackageStateAndReturn) {
- mRemovePackageHelper.clearPackageStateForUserLIF(ps, userId, outInfo, flags);
+ mRemovePackageHelper.clearPackageStateForUserLIF(ps, userId, flags);
+ // Legacy behavior to report appId as UID here.
+ // The final broadcasts will contain a per-user UID.
+ outInfo.mUid = ps.getAppId();
+ outInfo.mIsAppIdRemoved = true;
mPm.scheduleWritePackageRestrictions(user);
return;
}
@@ -529,12 +539,8 @@ final class DeletePackageHelper {
// If the package removed had SUSPEND_APPS, unset any restrictions that might have been in
// place for all affected users.
- int[] affectedUserIds = (outInfo != null) ? outInfo.mRemovedUsers : null;
- if (affectedUserIds == null) {
- affectedUserIds = mPm.resolveUserIds(userId);
- }
final Computer snapshot = mPm.snapshotComputer();
- for (final int affectedUserId : affectedUserIds) {
+ for (final int affectedUserId : outInfo.mRemovedUsers) {
if (hadSuspendAppsPermission.get(affectedUserId)) {
mPm.unsuspendForSuspendingPackage(snapshot, packageName, affectedUserId);
mPm.removeAllDistractingPackageRestrictions(snapshot, affectedUserId);
@@ -542,24 +548,21 @@ final class DeletePackageHelper {
}
// Take a note whether we deleted the package for all users
- if (outInfo != null) {
- synchronized (mPm.mLock) {
- outInfo.mRemovedForAllUsers = mPm.mPackages.get(ps.getPackageName()) == null;
- }
+ synchronized (mPm.mLock) {
+ outInfo.mRemovedForAllUsers = mPm.mPackages.get(ps.getPackageName()) == null;
}
}
@GuardedBy("mPm.mInstallLock")
private void deleteInstalledPackageLIF(PackageSetting ps,
boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
- PackageRemovedInfo outInfo, boolean writeSettings) {
+ @NonNull PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mPm.mLock) {
- if (outInfo != null) {
- outInfo.mUid = ps.getAppId();
- outInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
- mPm.snapshotComputer(), ps, allUserHandles,
- mPm.mSettings.getPackagesLocked());
- }
+ // Since the package is being deleted in all users, report appId as the uid
+ outInfo.mUid = ps.getAppId();
+ outInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
+ mPm.snapshotComputer(), ps, allUserHandles,
+ mPm.mSettings.getPackagesLocked());
}
// Delete package data from internal structures and also remove data if flag is set
@@ -567,7 +570,7 @@ final class DeletePackageHelper {
ps, allUserHandles, outInfo, flags, writeSettings);
// Delete application code and resources only for parent packages
- if (deleteCodeAndResources && (outInfo != null)) {
+ if (deleteCodeAndResources) {
outInfo.mArgs = new InstallArgs(
ps.getPathString(), getAppDexInstructionSets(
ps.getPrimaryCpuAbiLegacy(), ps.getSecondaryCpuAbiLegacy()));
@@ -639,7 +642,7 @@ final class DeletePackageHelper {
int flags = action.mFlags;
final PackageSetting deletedPs = action.mDeletingPs;
final PackageRemovedInfo outInfo = action.mRemovedInfo;
- final boolean applyUserRestrictions = outInfo != null && (outInfo.mOrigUsers != null);
+ final boolean applyUserRestrictions = outInfo.mOrigUsers != null;
final AndroidPackage deletedPkg = deletedPs.getPkg();
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
@@ -662,10 +665,8 @@ final class DeletePackageHelper {
}
}
- if (outInfo != null) {
- // Delete the updated package
- outInfo.mIsRemovedPackageSystemUpdate = true;
- }
+ // Delete the updated package
+ outInfo.mIsRemovedPackageSystemUpdate = true;
if (disabledPs.getVersionCode() < deletedPs.getVersionCode()
|| disabledPs.getAppId() != deletedPs.getAppId()) {
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index 24a33f1949fa..e3bbd2d8d17e 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -951,20 +951,32 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Deprecated
public final boolean isPackageSuspendedForUser(@NonNull String packageName,
@UserIdInt int userId) {
- return snapshot().isPackageSuspendedForUser(packageName, userId);
+ try {
+ return snapshot().isPackageSuspendedForUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
+ }
}
@Override
@Deprecated
public final boolean isPackageQuarantinedForUser(@NonNull String packageName,
@UserIdInt int userId) {
- return snapshot().isPackageQuarantinedForUser(packageName, userId);
+ try {
+ return snapshot().isPackageQuarantinedForUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
+ }
}
@Override
public final boolean isPackageStoppedForUser(@NonNull String packageName,
@UserIdInt int userId) {
- return snapshot().isPackageStoppedForUser(packageName, userId);
+ try {
+ return snapshot().isPackageStoppedForUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 5c4447eb99a4..3b9f9c804e27 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
@@ -30,7 +31,6 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -46,12 +46,12 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.om.OverlayConfig;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArrayMap;
import java.io.File;
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 83a6f10f0e2a..0fa7aa5473b2 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -154,12 +154,16 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.F2fsUtils;
+import com.android.internal.pm.parsing.PackageParserException;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -181,8 +185,6 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedLibraryWrapper;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.FileIntegrityService;
import com.android.server.utils.WatchedArrayMap;
@@ -1165,7 +1167,7 @@ final class InstallPackageHelper {
parseFlags);
archivedPackage = request.getPackageLite().getArchivedPackage();
}
- } catch (PackageManagerException e) {
+ } catch (PackageManagerException | PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -2450,9 +2452,9 @@ final class InstallPackageHelper {
// Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
mAppDataHelper.prepareAppDataPostCommitLIF(ps, 0, installRequest.getNewUsers());
if (installRequest.isClearCodeCache()) {
- mAppDataHelper.clearAppDataLeafLIF(packageName, ps.getVolumeUuid(),
- UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ mAppDataHelper.clearAppDataLIF(ps.getPkg(), UserHandle.USER_ALL,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
+ | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
if (installRequest.isInstallReplace() && pkg != null) {
mDexManager.notifyPackageUpdated(packageName,
@@ -2910,7 +2912,8 @@ final class InstallPackageHelper {
info.mInstallerPackageName = request.getInstallerPackageName();
info.mRemovedUsers = firstUserIds;
info.mBroadcastUsers = firstUserIds;
- info.mRemovedAppId = request.getAppId();
+ info.mUid = request.getAppId();
+ info.mIsAppIdRemoved = true;
info.mRemovedPackageVersionCode = request.getPkg().getLongVersionCode();
info.mRemovedForAllUsers = true;
@@ -3856,7 +3859,7 @@ final class InstallPackageHelper {
synchronized (mPm.mLock) {
platformPackage = mPm.getPlatformPackage();
- var isSystemApp = AndroidPackageUtils.isSystem(parsedPackage);
+ var isSystemApp = AndroidPackageLegacyUtils.isSystem(parsedPackage);
final String renamedPkgName = mPm.mSettings.getRenamedPackageLPr(
AndroidPackageUtils.getRealPackageOrNull(parsedPackage, isSystemApp));
realPkgName = ScanPackageUtils.getRealPackageName(parsedPackage, renamedPkgName,
@@ -4126,7 +4129,7 @@ final class InstallPackageHelper {
null /* request */)) {
mDeletePackageHelper.deletePackageLIF(
parsedPackage.getPackageName(), null, true,
- mPm.mUserManager.getUserIds(), 0, null, false);
+ mPm.mUserManager.getUserIds(), 0, new PackageRemovedInfo(), false);
}
} else if (newPkgVersionGreater || newSharedUserSetting) {
// The application on /system is newer than the application on /data.
@@ -4574,7 +4577,7 @@ final class InstallPackageHelper {
private void assertPackageWithSharedUserIdIsPrivileged(AndroidPackage pkg)
throws PackageManagerException {
- if (!AndroidPackageUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) {
+ if (!AndroidPackageLegacyUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) {
SharedUserSetting sharedUserSetting = null;
try {
synchronized (mPm.mLock) {
@@ -4612,7 +4615,7 @@ final class InstallPackageHelper {
final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0)
&& ScanPackageUtils.getVendorPartitionVersion() < 28;
if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
- && !AndroidPackageUtils.isPrivileged(pkg)
+ && !AndroidPackageLegacyUtils.isPrivileged(pkg)
&& (pkg.getSharedUserId() != null)
&& !skipVendorPrivilegeScan) {
SharedUserSetting sharedUserSetting = null;
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 5494bd9808c8..ee780d99b6b6 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -51,12 +51,12 @@ import android.util.ExceptionUtils;
import android.util.Slog;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.art.model.DexoptResult;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.util.ArrayList;
@@ -818,7 +818,8 @@ final class InstallRequest {
public void setRemovedAppId(int appId) {
if (mRemovedInfo != null) {
- mRemovedInfo.mRemovedAppId = appId;
+ mRemovedInfo.mUid = appId;
+ mRemovedInfo.mIsAppIdRemoved = true;
}
}
diff --git a/services/core/java/com/android/server/pm/KnownPackages.java b/services/core/java/com/android/server/pm/KnownPackages.java
index 154709a62095..83831ca61aa1 100644
--- a/services/core/java/com/android/server/pm/KnownPackages.java
+++ b/services/core/java/com/android/server/pm/KnownPackages.java
@@ -77,6 +77,8 @@ public final class KnownPackages {
// Please note the numbers should be continuous.
public static final int LAST_KNOWN_PACKAGE = PACKAGE_WEARABLE_SENSING;
+ static final String SYSTEM_PACKAGE_NAME = "android";
+
private final DefaultAppProvider mDefaultAppProvider;
private final String mRequiredInstallerPackage;
private final String mRequiredUninstallerPackage;
@@ -186,7 +188,7 @@ public final class KnownPackages {
case PACKAGE_SETUP_WIZARD:
return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
case PACKAGE_SYSTEM:
- return new String[]{"android"};
+ return new String[]{SYSTEM_PACKAGE_NAME};
case PACKAGE_VERIFIER:
return snapshot.filterOnlySystemPackages(mRequiredVerifierPackages);
case PACKAGE_SYSTEM_TEXT_CLASSIFIER:
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 58c1c0564f95..127bf495d2ac 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -822,7 +822,7 @@ public class LauncherAppsService extends SystemService {
return new LauncherActivityInfoInternal(
activityInfo,
new IncrementalStatesInfo(
- false /* isLoading */, 1 /* progress */, 0 /* loadingCompletedTime */),
+ false /* isLoading */, 0 /* progress */, 0 /* loadingCompletedTime */),
user);
}
@@ -1575,6 +1575,57 @@ public class LauncherAppsService extends SystemService {
}
@Override
+ public List<String> getPreInstalledSystemPackages(UserHandle user) {
+ // Only system launchers, which have access to recents should have access to this API.
+ // TODO(b/303803157): Update access control for this API to default Launcher app.
+ if (!mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) {
+ throw new SecurityException("Caller is not the recents app");
+ }
+ if (!canAccessProfile(user.getIdentifier(),
+ "Can't access preinstalled packages for another user")) {
+ return null;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ String userType = mUm.getUserInfo(user.getIdentifier()).userType;
+ Set<String> preInstalledPackages = mUm.getPreInstallableSystemPackages(userType);
+ if (preInstalledPackages == null) {
+ return new ArrayList<>();
+ }
+ return List.copyOf(preInstalledPackages);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public @Nullable IntentSender getAppMarketActivityIntent(@NonNull String callingPackage,
+ @Nullable String packageName, @NonNull UserHandle user) {
+ // Only system launchers, which have access to recents should have access to this API.
+ // TODO(b/303803157): Update access control for this API to default Launcher app.
+ if (!mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) {
+ throw new SecurityException("Caller is not the recents app");
+ }
+ if (!canAccessProfile(user.getIdentifier(),
+ "Can't access AppMarketActivity for another user")) {
+ return null;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ // TODO(b/316118005): Add code to launch the app installer for the packageName.
+ Intent appMarketIntent = new Intent(Intent.ACTION_MAIN);
+ appMarketIntent.addCategory(Intent.CATEGORY_APP_MARKET);
+ final PendingIntent pi = PendingIntent.getActivityAsUser(
+ mContext, /* requestCode */ 0, appMarketIntent, PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
+ /* options */ null, user);
+ return pi == null ? null : pi.getIntentSender();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index e3bab3f243c3..2864a8b42445 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -165,7 +165,7 @@ public class PackageArchiver {
Computer snapshot = mPm.snapshotComputer();
int userId = userHandle.getIdentifier();
int binderUid = Binder.getCallingUid();
- if (!PackageManagerServiceUtils.isRootOrShell(binderUid)) {
+ if (!PackageManagerServiceUtils.isSystemOrRootOrShell(binderUid)) {
verifyCaller(snapshot.getPackageUid(callerPackageName, 0, userId), binderUid);
}
snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
@@ -323,6 +323,7 @@ public class PackageArchiver {
PackageStateInternal ps = getPackageState(packageName, snapshot,
Binder.getCallingUid(), userId);
verifyNotSystemApp(ps.getFlags());
+ verifyInstalled(ps, userId);
String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
verifyInstaller(responsibleInstallerPackage, userId);
ApplicationInfo installerInfo = snapshot.getApplicationInfo(
@@ -476,6 +477,14 @@ public class PackageArchiver {
}
}
+ private void verifyInstalled(PackageStateInternal ps, int userId)
+ throws PackageManager.NameNotFoundException {
+ if (!ps.getUserStateOrDefault(userId).isInstalled()) {
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("%s is not installed.", ps.getPackageName()));
+ }
+ }
+
/**
* Returns true if the app is archivable.
*/
@@ -519,11 +528,11 @@ public class PackageArchiver {
/**
* Returns true if user has opted the app out of archiving through system settings.
*/
- // TODO(b/304256918) Switch this to a separate OP code for archiving.
private boolean isAppOptedOutOfArchiving(String packageName, int uid) {
return Binder.withCleanCallingIdentity(() ->
- getAppOpsManager().checkOp(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
- uid, packageName) == MODE_IGNORED);
+ getAppOpsManager().checkOpNoThrow(
+ AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, uid, packageName)
+ == MODE_IGNORED);
}
private void verifyOptOutStatus(String packageName, int uid)
@@ -676,23 +685,51 @@ public class PackageArchiver {
PackageStateInternal ps;
try {
ps = getPackageState(packageName, snapshot, callingUid, userId);
- snapshot.enforceCrossUserPermission(callingUid, userId, true, false,
- "getArchivedAppIcon");
- verifyArchived(ps, userId);
} catch (PackageManager.NameNotFoundException e) {
- throw new ParcelableException(e);
+ Slog.e(TAG, TextUtils.formatSimple("Package %s couldn't be found.", packageName), e);
+ return null;
}
- List<ArchiveActivityInfo> activityInfos = ps.getUserStateOrDefault(
- userId).getArchiveState().getActivityInfos();
- if (activityInfos.size() == 0) {
+ ArchiveState archiveState = getAnyArchiveState(ps, userId);
+ if (archiveState == null || archiveState.getActivityInfos().size() == 0) {
return null;
}
// TODO(b/298452477) Handle monochrome icons.
// In the rare case the archived app defined more than two launcher activities, we choose
// the first one arbitrarily.
- return includeCloudOverlay(decodeIcon(activityInfos.get(0)));
+ return includeCloudOverlay(decodeIcon(archiveState.getActivityInfos().get(0)));
+ }
+
+ /**
+ * This method first checks the ArchiveState for the provided userId and then tries to fallback
+ * to other users if the current user is not archived.
+ *
+ * <p> This fallback behaviour is required for archived apps to fit into the multi-user world
+ * where APKs are shared across users. E.g. current ways of fetching icons for apps that are
+ * only installed on the work profile also work when executed on the personal profile if you're
+ * using {@link PackageManager#MATCH_UNINSTALLED_PACKAGES}. Resource fetching from APKs is for
+ * the most part userId-agnostic, which we need to mimic here in order for existing methods
+ * like {@link PackageManager#getApplicationIcon} to continue working.
+ *
+ * @return {@link ArchiveState} for {@code userId} if present. If not present, false back to an
+ * arbitrary userId. If no user is archived, returns null.
+ */
+ @Nullable
+ private ArchiveState getAnyArchiveState(PackageStateInternal ps, int userId) {
+ PackageUserStateInternal userState = ps.getUserStateOrDefault(userId);
+ if (isArchived(userState)) {
+ return userState.getArchiveState();
+ }
+
+ for (int i = 0; i < ps.getUserStates().size(); i++) {
+ userState = ps.getUserStates().valueAt(i);
+ if (isArchived(userState)) {
+ return userState.getArchiveState();
+ }
+ }
+
+ return null;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7d6dd62153c1..2942bbb86e62 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -821,6 +821,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
params.installFlags &= ~PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;
}
+ params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE;
+ if (Flags.archiving() && params.appPackageName != null) {
+ PackageStateInternal ps = mPm.snapshotComputer().getPackageStateInternal(
+ params.appPackageName, SYSTEM_UID);
+ if (ps != null
+ && PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))
+ && PackageArchiver.getResponsibleInstallerPackage(ps)
+ .equals(requestedInstallerPackageName)) {
+ params.installFlags |= PackageManager.INSTALL_UNARCHIVE;
+ }
+ }
+
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
&& !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)
&& (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 47d1df5df1c0..4adb60c34c52 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -168,6 +168,7 @@ import com.android.internal.content.InstallLocationUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.os.SomeArgs;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -181,7 +182,6 @@ import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 1e7d0437d99e..8da168375447 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -19,6 +19,8 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -37,6 +39,7 @@ import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -250,7 +253,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
getSuspendPackageHelper().removeSuspensionsBySuspendingPackage(snapshot(),
new String[]{packageName},
(suspendingPackage) -> !PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
- suspendingPackage),
+ suspendingPackage.packageName),
userId);
}
@@ -269,7 +272,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
- public final String getSuspendingPackage(String suspendedPackage, int userId) {
+ public final UserPackage getSuspendingPackage(String suspendedPackage, int userId) {
return getSuspendPackageHelper().getSuspendingPackage(snapshot(), suspendedPackage, userId,
Binder.getCallingUid());
}
@@ -277,7 +280,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
public final SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId) {
+ UserPackage suspendingPackage, int userId) {
return getSuspendPackageHelper().getSuspendedDialogInfo(snapshot(), suspendedPackage,
suspendingPackage, userId, Binder.getCallingUid());
}
@@ -683,14 +686,16 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
- public final void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
- mService.unsuspendForSuspendingPackage(snapshot(), packageName, affectedUser);
+ public final void unsuspendAdminSuspendedPackages(int affectedUser) {
+ final int suspendingUserId = affectedUser;
+ mService.unsuspendForSuspendingPackage(snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId);
}
@Override
@Deprecated
- public final boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
- return snapshot().isSuspendingAnyPackages(suspendingPackage, userId);
+ public final boolean isAdminSuspendingAnyPackages(int userId) {
+ final int suspendingUserId = userId;
+ return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId);
}
@Override
@@ -762,13 +767,14 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
}
@Override
- public boolean isPackageQuarantined(@NonNull String packageName,
- @UserIdInt int userId) {
+ public boolean isPackageQuarantined(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
return snapshot().isPackageQuarantinedForUser(packageName, userId);
}
@Override
- public boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId) {
+ public boolean isPackageStopped(@NonNull String packageName, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
return snapshot().isPackageStoppedForUser(packageName, userId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2880f84c6445..bc441b84c58b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -185,6 +185,7 @@ import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -238,7 +239,6 @@ import com.android.server.pm.pkg.SharedUserApi;
import com.android.server.pm.pkg.mutate.PackageStateMutator;
import com.android.server.pm.pkg.mutate.PackageStateWrite;
import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.resolution.ComponentResolver;
import com.android.server.pm.resolution.ComponentResolverApi;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
@@ -292,6 +292,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Keep track of all those APKs everywhere.
@@ -2013,6 +2014,16 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
};
// CHECKSTYLE:ON IndentationCheck
@@ -3044,6 +3055,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
+ @NonNull
int[] resolveUserIds(int userId) {
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
@@ -3126,7 +3138,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot,
- boolean quarantined, String callingPackage, int callingUid, int userId,
+ boolean quarantined, UserPackage suspender, int callingUid, int targetUserId,
String callingMethod) {
if (callingUid == Process.ROOT_UID
// Need to compare app-id to allow system dialogs access on secondary users
@@ -3134,9 +3146,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return;
}
- final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ final String ownerPackage =
+ mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
if (ownerPackage != null) {
- final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, userId);
+ final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, targetUserId);
if (ownerUid == callingUid) {
return;
}
@@ -3157,25 +3170,27 @@ public class PackageManagerService implements PackageSender, TestUtilityService
callingMethod);
}
- final int packageUid = snapshot.getPackageUid(callingPackage, 0, userId);
+ final int packageUid = snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
final boolean allowedPackageUid = packageUid == callingUid;
// TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
final boolean allowedShell = callingUid == SHELL_UID
&& UserHandle.isSameApp(packageUid, callingUid);
if (!allowedShell && !allowedPackageUid) {
- throw new SecurityException("Calling package " + callingPackage + " in user "
- + userId + " does not belong to calling uid " + callingUid);
+ throw new SecurityException("Suspending package " + suspender.packageName
+ + " in user " + targetUserId + " does not belong to calling uid " + callingUid);
}
}
void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
- @UserIdInt int userId) {
+ @UserIdInt int suspendingUserId) {
// TODO: This can be replaced by a special parameter to iterate all packages, rather than
// this weird pre-collect of all packages.
final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]);
+ final Predicate<UserPackage> suspenderPredicate =
+ UserPackage.of(suspendingUserId, suspendingPackage)::equals;
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
- allPackages, suspendingPackage::equals, userId);
+ allPackages, suspenderPredicate, suspendingUserId);
}
void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
@@ -5241,14 +5256,19 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String getSuspendingPackage(String packageName, int userId) {
- final int callingUid = Binder.getCallingUid();
- final Computer snapshot = snapshot();
- // This will do visibility checks as well.
- if (!snapshot.isPackageSuspendedForUser(packageName, userId)) {
+ try {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshot();
+ // This will do visibility checks as well.
+ if (!snapshot.isPackageSuspendedForUser(packageName, userId)) {
+ return null;
+ }
+ final UserPackage suspender = mSuspendPackageHelper.getSuspendingPackage(
+ snapshot, packageName, userId, callingUid);
+ return suspender != null ? suspender.packageName : null;
+ } catch (PackageManager.NameNotFoundException e) {
return null;
}
- return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
- callingUid);
}
@Override
@@ -6183,7 +6203,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
- SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId) {
+ SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
+ int suspendingUserId, int targetUserId) {
final int callingUid = Binder.getCallingUid();
boolean quarantined = false;
if (Flags.quarantinedEnabled()) {
@@ -6192,14 +6213,15 @@ public class PackageManagerService implements PackageSender, TestUtilityService
} else if (FeatureFlagUtils.isEnabled(mContext,
SETTINGS_TREAT_PAUSE_AS_QUARANTINE)) {
final String wellbeingPkg = mContext.getString(R.string.config_systemWellbeing);
- quarantined = callingPackage.equals(wellbeingPkg);
+ quarantined = suspendingPackage.equals(wellbeingPkg);
}
}
final Computer snapshot = snapshotComputer();
- enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, callingPackage, callingUid,
- userId, "setPackagesSuspendedAsUser");
+ final UserPackage suspender = UserPackage.of(targetUserId, suspendingPackage);
+ enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, suspender, callingUid,
+ targetUserId, "setPackagesSuspendedAsUser");
return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
- appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid,
+ appExtras, launcherExtras, dialogInfo, suspender, targetUserId, callingUid,
quarantined);
}
@@ -6638,7 +6660,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final Computer computer = snapshotComputer();
final String[] allPackages = computer.getAllAvailablePackageNames();
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
- (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ (suspender) -> !PLATFORM_PACKAGE_NAME.equals(suspender.packageName),
userId);
}
@@ -6652,8 +6674,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String[] setPackagesSuspendedByAdmin(
@UserIdInt int userId, @NonNull String[] packageNames, boolean suspended) {
- return mSuspendPackageHelper.setPackagesSuspendedByAdmin(
- snapshotComputer(), userId, packageNames, suspended);
+ final int suspendingUserId = userId;
+ final UserPackage suspender = UserPackage.of(
+ suspendingUserId, PackageManagerService.PLATFORM_PACKAGE_NAME);
+ return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
+ suspended, null /* appExtras */, null /* launcherExtras */,
+ null /* dialogInfo */, suspender, userId, Process.SYSTEM_UID,
+ false /* quarantined */);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 215e9528a35e..243fb16b19ae 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2827,7 +2827,7 @@ class PackageManagerShellCommand extends ShellCommand {
mInterface.setPackagesSuspendedAsUser(packageNames.toArray(new String[] {}),
suspendedState, ((appExtras.size() > 0) ? appExtras : null),
((launcherExtras.size() > 0) ? launcherExtras : null),
- info, flags, callingPackage, translatedUserId);
+ info, flags, callingPackage, UserHandle.USER_SYSTEM, translatedUserId);
for (int i = 0; i < packageNames.size(); i++) {
final String packageName = packageNames.get(i);
pw.println("Package " + packageName + " new suspended state: "
@@ -2872,16 +2872,16 @@ class PackageManagerShellCommand extends ShellCommand {
UserHandle.USER_NULL, "runGrantRevokePermission"));
List<PackageInfo> packageInfos;
+ PackageManager pm = mContext.createContextAsUser(translatedUser, 0).getPackageManager();
if (pkg == null) {
- packageInfos = mContext.getPackageManager().getInstalledPackages(
- PackageManager.GET_PERMISSIONS);
+ packageInfos = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
} else {
try {
- packageInfos = Collections.singletonList(
- mContext.getPackageManager().getPackageInfo(pkg,
- PackageManager.GET_PERMISSIONS));
+ packageInfos = Collections.singletonList(pm.getPackageInfo(pkg,
+ PackageManager.GET_PERMISSIONS));
} catch (NameNotFoundException e) {
getErrPrintWriter().println("Error: package not found");
+ getOutPrintWriter().println("Failure [package not found]");
return 1;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index 7ee1772adead..881b0b398f9a 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -25,7 +25,7 @@ final class PackageRemovedInfo {
String mRemovedPackage;
String mInstallerPackageName;
int mUid = -1;
- int mRemovedAppId = -1;
+ boolean mIsAppIdRemoved = false;
int[] mOrigUsers;
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7d0a1f6afe1d..28a90f3d6ab6 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,6 +32,7 @@ import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
@@ -952,7 +953,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
void setUserState(int userId, long ceDataInode, long deDataInode, int enabled,
boolean installed, boolean stopped, boolean notLaunched, boolean hidden,
- int distractionFlags, ArrayMap<String, SuspendParams> suspendParams,
+ int distractionFlags, ArrayMap<UserPackage, SuspendParams> suspendParams,
boolean instantApp, boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int installReason, int uninstallReason,
@@ -1182,7 +1183,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
if (state.isSuspended()) {
for (int j = 0; j < state.getSuspendParams().size(); j++) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
- state.getSuspendParams().keyAt(j));
+ state.getSuspendParams().keyAt(j).packageName);
}
}
proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.isStopped());
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index bb0017c80d6d..b6de0e5c030f 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -20,19 +20,23 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIB
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
+import static com.android.server.pm.PackageManagerService.TAG;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
+import android.os.Build;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedLongSparseArray;
import java.util.ArrayList;
@@ -49,6 +53,8 @@ import java.util.Map;
* as install) led to the request.
*/
final class ReconcilePackageUtils {
+ private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE || true;
+
public static List<ReconciledPackage> reconcilePackages(
List<InstallRequest> installRequests,
Map<String, AndroidPackage> allPackages,
@@ -90,6 +96,8 @@ final class ReconcilePackageUtils {
}
}
+ final AndroidPackage systemPackage = allPackages.get(KnownPackages.SYSTEM_PACKAGE_NAME);
+
for (InstallRequest installRequest : installRequests) {
final String installPackageName = installRequest.getParsedPackage().getPackageName();
final List<SharedLibraryInfo> allowedSharedLibInfos =
@@ -133,6 +141,9 @@ final class ReconcilePackageUtils {
if (parsedPackage != null) {
signingDetails = parsedPackage.getSigningDetails();
}
+ final boolean isSystemPackage =
+ ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0);
+ final boolean isApex = (scanFlags & SCAN_AS_APEX) != 0;
SharedUserSetting sharedUserSetting = settings.getSharedUserSettingLPr(
signatureCheckPs);
if (ksms.shouldCheckUpgradeKeySetLocked(
@@ -141,7 +152,7 @@ final class ReconcilePackageUtils {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
} else {
- if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
+ if (!isSystemPackage) {
throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + parsedPackage.getPackageName()
+ " upgrade keys do not match the previously installed"
@@ -168,9 +179,23 @@ final class ReconcilePackageUtils {
removeAppKeySetData = true;
}
+ if (!isSystemPackage && !isApex && signingDetails != null
+ && systemPackage != null && systemPackage.getSigningDetails() != null
+ && systemPackage.getSigningDetails().checkCapability(
+ signingDetails,
+ SigningDetails.CertCapabilities.PERMISSION)) {
+ Slog.d(TAG, "Non-preload app associated with system signature: "
+ + signatureCheckPs.getPackageName());
+ if (!ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE) {
+ throw new ReconcileFailure(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ "Non-preload app associated with system signature: "
+ + signatureCheckPs.getPackageName());
+ }
+ }
+
// if this is is a sharedUser, check to see if the new package is signed by a
- // newer
- // signing certificate than the existing one, and if so, copy over the new
+ // newer signing certificate than the existing one, and if so, copy over the new
// details
if (sharedUserSetting != null) {
// Attempt to merge the existing lineage for the shared SigningDetails with
@@ -203,7 +228,7 @@ final class ReconcilePackageUtils {
}
}
} catch (PackageManagerException e) {
- if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
+ if (!isSystemPackage) {
throw new ReconcileFailure(e);
}
signingDetails = parsedPackage.getSigningDetails();
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 52b31319cc19..f42b43f5aeef 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -44,12 +44,12 @@ import android.util.Slog;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.parsing.PackageCacher;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -167,7 +167,7 @@ final class RemovePackageHelper {
if (removedPackage != null) {
// TODO: Use PackageState for isSystem
cleanPackageDataStructuresLILPw(removedPackage,
- AndroidPackageUtils.isSystem(removedPackage), chatty);
+ AndroidPackageLegacyUtils.isSystem(removedPackage), chatty);
}
}
}
@@ -252,88 +252,129 @@ final class RemovePackageHelper {
}
}
- public void clearPackageStateForUserLIF(PackageSetting ps, int userId,
- PackageRemovedInfo outInfo, int flags) {
+ /**
+ * This method clears the data and states stored in the system that are related to the
+ * package being deleted and the target user, including the data directory.
+ * If the DELETE_KEEP_DATA flag is set, everything is preserved except ART profiles.
+ * Make sure this flag is set for partially installed apps. If not it's meaningless to
+ * delete a partially installed application.
+ */
+ public void clearPackageStateForUserLIF(PackageSetting ps, int userId, int flags) {
+ final String packageName = ps.getPackageName();
+ // Step 1: always destroy app profiles.
+ mAppDataHelper.destroyAppProfilesLIF(packageName);
+
+ // Everything else is preserved if the DELETE_KEEP_DATA flag is on
+ if ((flags & PackageManager.DELETE_KEEP_DATA) != 0) {
+ return;
+ }
+
final AndroidPackage pkg;
final SharedUserSetting sus;
synchronized (mPm.mLock) {
- pkg = mPm.mPackages.get(ps.getPackageName());
+ pkg = mPm.mPackages.get(packageName);
sus = mPm.mSettings.getSharedUserSettingLPr(ps);
}
- mAppDataHelper.destroyAppProfilesLIF(ps.getPackageName());
+ final AndroidPackage resolvedPkg;
+ if (pkg != null) {
+ resolvedPkg = pkg;
+ } else {
+ // We don't have a parsed package when it lives on an ejected
+ // adopted storage device, so fake something together
+ resolvedPkg = PackageImpl.buildFakeForDeletion(packageName, ps.getVolumeUuid());
+ }
+
+ // Step 2: destroy app data.
+ mAppDataHelper.destroyAppDataLIF(resolvedPkg, userId,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+ if (userId != UserHandle.USER_ALL) {
+ ps.setCeDataInode(-1, userId);
+ ps.setDeDataInode(-1, userId);
+ }
- final List<AndroidPackage> sharedUserPkgs =
- sus != null ? sus.getPackages() : Collections.emptyList();
final PreferredActivityHelper preferredActivityHelper = new PreferredActivityHelper(mPm,
mBroadcastHelper);
- final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManagerInternal.getUserIds()
- : new int[] {userId};
- for (int nextUserId : userIds) {
+ if (userId == UserHandle.USER_ALL) {
if (DEBUG_REMOVE) {
- Slog.d(TAG, "Updating package:" + ps.getPackageName() + " install state for user:"
- + nextUserId);
+ Slog.d(TAG, "Clear package:" + packageName + " state for all users");
+ }
+ // Step 3: inform DomainVerificationManager.
+ mPm.mDomainVerificationManager.clearPackage(packageName);
+ synchronized (mPm.mLock) {
+ // Step 3.1 (only for USER_ALL): notify KeySetManagerService.
+ mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
+ // Step 3.2 (only for USER_ALL): update installer ownership.
+ mPm.mInjector.getUpdateOwnershipHelper().removeUpdateOwnerDenyList(packageName);
+ // Step 3.3 (only for USER_ALL): update AppsFilter.
+ final Computer snapshot = mPm.snapshotComputer();
+ mPm.mAppsFilter.removePackage(snapshot,
+ snapshot.getPackageStateInternal(packageName));
+ // Step 4: clear perferred activities.
+ final SparseBooleanArray changedUsers = new SparseBooleanArray();
+ mPm.clearPackagePreferredActivitiesLPw(
+ packageName, changedUsers, UserHandle.USER_ALL);
+ mPm.mInjector.getBackgroundHandler().post(() -> {
+ if (changedUsers.size() > 0) {
+ preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
+ changedUsers);
+ mBroadcastHelper.sendPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
+ }
+ });
+ // Step 5: inform PermissionManager.
+ // This has to be done after the removal from mSettings in removePackageDataLIF.
}
- if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- mAppDataHelper.destroyAppDataLIF(pkg, nextUserId,
- FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
- ps.setCeDataInode(-1, nextUserId);
- ps.setDeDataInode(-1, nextUserId);
+ } else {
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, "Clear package:" + packageName + " state for user:" + userId);
}
- mAppDataHelper.clearKeystoreData(nextUserId, ps.getAppId());
- preferredActivityHelper.clearPackagePreferredActivities(ps.getPackageName(),
- nextUserId);
- mPm.mDomainVerificationManager.clearPackageForUser(ps.getPackageName(), nextUserId);
+ // Step 3: inform DomainVerificationManager.
+ mPm.mDomainVerificationManager.clearPackageForUser(packageName, userId);
+ // Step 4: clear perferred activities.
+ preferredActivityHelper.clearPackagePreferredActivities(packageName, userId);
+ // Step 5: inform PermissionManager.
+ List<AndroidPackage> sharedUserPkgs =
+ sus != null ? sus.getPackages() : Collections.emptyList();
+ mPermissionManager.onPackageUninstalled(packageName, ps.getAppId(), ps, pkg,
+ sharedUserPkgs, userId);
}
- mPermissionManager.onPackageUninstalled(ps.getPackageName(), ps.getAppId(), ps, pkg,
- sharedUserPkgs, userId);
- if (outInfo != null) {
- if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- outInfo.mDataRemoved = true;
+ // Step 6: detroy keystore data.
+ mPm.mInjector.getBackgroundHandler().post(() -> {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
+ "clearKeystoreData:" + ps.getAppId() + " for user: " + userId);
+ mAppDataHelper.clearKeystoreData(userId, ps.getAppId());
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- outInfo.mRemovedPackage = ps.getPackageName();
- outInfo.mInstallerPackageName = ps.getInstallSource().mInstallerPackageName;
- outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibraryName() != null;
- outInfo.mRemovedAppId = ps.getAppId();
- outInfo.mBroadcastUsers = outInfo.mRemovedUsers;
- outInfo.mIsExternal = ps.isExternalStorage();
- outInfo.mRemovedPackageVersionCode = ps.getVersionCode();
- }
+ });
}
// Called to clean up disabled system packages
public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles) {
synchronized (mPm.mInstallLock) {
- removePackageDataLIF(deletedPs, allUserHandles, /* outInfo= */ null,
+ removePackageDataLIF(deletedPs, allUserHandles, new PackageRemovedInfo(),
/* flags= */ 0, /* writeSettings= */ false);
}
}
/*
- * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
- * flag is not set, the data directory is removed as well.
- * make sure this flag is set for partially installed apps. If not it's meaningless to
- * delete a partially installed application.
+ * This method deletes the package from internal data structures such as mPackages / mSettings.
*/
@GuardedBy("mPm.mInstallLock")
public void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
- PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
+ @NonNull PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = deletedPs.getPackageName();
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
// Retrieve object to delete permissions for shared user later on
final AndroidPackage deletedPkg = deletedPs.getPkg();
- if (outInfo != null) {
- outInfo.mRemovedPackage = packageName;
- outInfo.mInstallerPackageName = deletedPs.getInstallSource().mInstallerPackageName;
- outInfo.mIsStaticSharedLib = deletedPkg != null
- && deletedPkg.getStaticSharedLibraryName() != null;
- outInfo.populateBroadcastUsers(deletedPs);
- outInfo.mIsExternal = deletedPs.isExternalStorage();
- outInfo.mRemovedPackageVersionCode = deletedPs.getVersionCode();
- }
- removePackageLI(deletedPs.getPackageName(), (flags & PackageManager.DELETE_CHATTY) != 0);
+ // Delete all the data and states related to this package.
+ clearPackageStateForUserLIF(deletedPs, UserHandle.USER_ALL, flags);
+
+ // Delete from mPackages
+ removePackageLI(packageName, (flags & PackageManager.DELETE_CHATTY) != 0);
if (!deletedPs.isSystem()) {
// A non-system app's AndroidPackage object has been removed from the service.
// Explicitly nullify the corresponding app's PackageSetting's pkg object to
@@ -343,44 +384,16 @@ final class RemovePackageHelper {
}
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
- final AndroidPackage resolvedPkg;
- if (deletedPkg != null) {
- resolvedPkg = deletedPkg;
- } else {
- // We don't have a parsed package when it lives on an ejected
- // adopted storage device, so fake something together
- resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.getPackageName(),
- deletedPs.getVolumeUuid());
- }
- mAppDataHelper.destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
- FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
- mAppDataHelper.destroyAppProfilesLIF(resolvedPkg.getPackageName());
- if (outInfo != null) {
- outInfo.mDataRemoved = true;
- }
- }
-
- int removedAppId = -1;
-
- // writer
- if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ // Delete from mSettings
final SparseBooleanArray changedUsers = new SparseBooleanArray();
synchronized (mPm.mLock) {
- mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName());
- mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
- mPm.mInjector.getUpdateOwnershipHelper().removeUpdateOwnerDenyList(packageName);
- final Computer snapshot = mPm.snapshotComputer();
- mPm.mAppsFilter.removePackage(snapshot,
- snapshot.getPackageStateInternal(packageName));
- removedAppId = mPm.mSettings.removePackageLPw(packageName);
- if (outInfo != null) {
- outInfo.mRemovedAppId = removedAppId;
- }
+ mPm.mSettings.removePackageLPw(packageName);
+ outInfo.mIsAppIdRemoved = true;
if (!mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
+ final SharedUserSetting sus = mPm.mSettings.getSharedUserSettingLPr(deletedPs);
// If we don't have a disabled system package to reinstall, the package is
// really gone and its permission state should be removed.
- SharedUserSetting sus = mPm.mSettings.getSharedUserSettingLPr(deletedPs);
- List<AndroidPackage> sharedUserPkgs =
+ final List<AndroidPackage> sharedUserPkgs =
sus != null ? sus.getPackages() : Collections.emptyList();
mPermissionManager.onPackageUninstalled(packageName, deletedPs.getAppId(),
deletedPs, deletedPkg, sharedUserPkgs, UserHandle.USER_ALL);
@@ -389,22 +402,10 @@ final class RemovePackageHelper {
mPm.mSettings.checkAndConvertSharedUserSettingsLPw(sus);
}
}
- mPm.clearPackagePreferredActivitiesLPw(
- deletedPs.getPackageName(), changedUsers, UserHandle.USER_ALL);
-
mPm.mSettings.removeRenamedPackageLPw(deletedPs.getRealName());
}
- if (changedUsers.size() > 0) {
- mPm.mInjector.getBackgroundHandler().post(() -> {
- final PreferredActivityHelper preferredActivityHelper =
- new PreferredActivityHelper(mPm, mBroadcastHelper);
- preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
- changedUsers);
- mBroadcastHelper.sendPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
- });
- }
- } else if (!deletedPs.isSystem() && outInfo != null && !outInfo.mIsUpdate
- && outInfo.mRemovedUsers != null && !outInfo.mIsExternal) {
+ } else if (!deletedPs.isSystem() && !outInfo.mIsUpdate
+ && outInfo.mRemovedUsers != null && !deletedPs.isExternalStorage()) {
// For non-system uninstalls with DELETE_KEEP_DATA, set the installed state to false
// for affected users. This does not apply to app updates where the old apk is replaced
// but the old data remains.
@@ -421,10 +422,11 @@ final class RemovePackageHelper {
deletedPs.setInstalled(/* installed= */ false, userId);
}
}
+
// make sure to preserve per-user installed state if this removal was just
// a downgrade of a system app to the factory package
boolean installedStateChanged = false;
- if (outInfo != null && outInfo.mOrigUsers != null && deletedPs.isSystem()) {
+ if (outInfo.mOrigUsers != null && deletedPs.isSystem()) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
@@ -452,20 +454,6 @@ final class RemovePackageHelper {
mPm.mSettings.writeKernelMappingLPr(deletedPs);
}
}
-
- if (removedAppId != -1) {
- // A user ID was deleted here. Go through all users and remove it from KeyStore.
- final int appIdToRemove = removedAppId;
- mPm.mInjector.getBackgroundHandler().post(() -> {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
- "clearKeystoreData:" + appIdToRemove);
- mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, appIdToRemove);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- });
- }
}
void cleanUpResources(File codeFile, String[] instructionSets) {
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 31a63e07b66c..5c6d61e3eaf9 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -74,11 +74,13 @@ import android.util.jar.StrictJarFile;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -86,8 +88,6 @@ import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateUtils;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArraySet;
import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index 37cf30bd63fe..41e2a3f3d318 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -22,8 +22,8 @@ import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
/** A package to be scanned */
@VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 75d88da059b5..cdf1f949a2d8 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -51,6 +51,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.overlay.OverlayPaths;
import android.net.Uri;
@@ -89,6 +90,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
@@ -106,7 +108,6 @@ import com.android.server.LocalServices;
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
@@ -1956,7 +1957,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
ArchiveState archiveState = null;
int packageDepth = parser.getDepth();
- ArrayMap<String, SuspendParams> suspendParamsMap = null;
+ ArrayMap<UserPackage, SuspendParams> suspendParamsMap = null;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > packageDepth)) {
@@ -1983,18 +1984,15 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
parser);
break;
case TAG_SUSPEND_PARAMS:
- final String suspendingPackage = parser.getAttributeValue(null,
- ATTR_SUSPENDING_PACKAGE);
- if (suspendingPackage == null) {
- Slog.wtf(TAG, "No suspendingPackage found inside tag "
- + TAG_SUSPEND_PARAMS);
+ Map.Entry<UserPackage, SuspendParams> entry =
+ readSuspensionParamsLPr(userId, parser);
+ if (entry == null) {
continue;
}
if (suspendParamsMap == null) {
suspendParamsMap = new ArrayMap<>();
}
- suspendParamsMap.put(suspendingPackage,
- SuspendParams.restoreFromXml(parser));
+ suspendParamsMap.put(entry.getKey(), entry.getValue());
break;
case TAG_ARCHIVE_STATE:
archiveState = parseArchiveState(parser);
@@ -2016,7 +2014,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
oldSuspendedLauncherExtras,
false /* quarantined */);
suspendParamsMap = new ArrayMap<>();
- suspendParamsMap.put(oldSuspendingPackage, suspendParams);
+ suspendParamsMap.put(
+ UserPackage.of(userId, oldSuspendingPackage), suspendParams);
}
if (blockUninstall) {
@@ -2058,6 +2057,20 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
}
+ @Nullable
+ private static Map.Entry<UserPackage, SuspendParams> readSuspensionParamsLPr(
+ int userId, TypedXmlPullParser parser) throws IOException {
+ final String suspendingPackage = parser.getAttributeValue(null, ATTR_SUSPENDING_PACKAGE);
+ if (suspendingPackage == null) {
+ Slog.wtf(TAG, "No suspendingPackage found inside tag " + TAG_SUSPEND_PARAMS);
+ return null;
+ }
+ final int suspendingUserId = userId;
+ return Map.entry(
+ UserPackage.of(suspendingUserId, suspendingPackage),
+ SuspendParams.restoreFromXml(parser));
+ }
+
private static ArchiveState parseArchiveState(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
String installerTitle = parser.getAttributeValue(null,
@@ -2414,10 +2427,11 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
if (ustate.isSuspended()) {
for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
- final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
+ final UserPackage suspendingPackage =
+ ustate.getSuspendParams().keyAt(i);
serializer.startTag(null, TAG_SUSPEND_PARAMS);
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
- suspendingPackage);
+ suspendingPackage.packageName);
final SuspendParams params =
ustate.getSuspendParams().valueAt(i);
if (params != null) {
@@ -2556,7 +2570,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
outPs.getUsesSdkLibraries(), libName));
outPs.setUsesSdkLibrariesVersionsMajor(ArrayUtils.appendLong(
outPs.getUsesSdkLibrariesVersionsMajor(), libVersion));
- outPs.setUsesSdkLibrariesOptional(PackageImpl.appendBoolean(
+ outPs.setUsesSdkLibrariesOptional(ArrayUtils.appendBoolean(
outPs.getUsesSdkLibrariesOptional(), optional));
}
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 94495bf462f2..ec8af2ecd070 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -731,7 +731,7 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable
? PackageManager.DELETE_KEEP_DATA : 0;
synchronized (mPm.mInstallLock) {
mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
- mPm.mUserManager.getUserIds(), flags, null,
+ mPm.mUserManager.getUserIds(), flags, new PackageRemovedInfo(),
true);
}
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index dddc6b0fbb7a..5c0a15a28285 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -25,14 +25,14 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessImpl;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedProcessImpl;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchedArraySet;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 70aa19ae9cef..7d87d1b27da0 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -47,11 +47,11 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.io.PrintWriter;
@@ -256,13 +256,12 @@ public final class StorageEventHelper extends StorageEventListener {
final AndroidPackage pkg = ps.getPkg();
final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
- final PackageRemovedInfo outInfo = new PackageRemovedInfo();
try (PackageFreezer freezer = mPm.freezePackageForDelete(ps.getPackageName(),
UserHandle.USER_ALL, deleteFlags,
"unloadPrivatePackagesInner", ApplicationExitInfo.REASON_OTHER)) {
if (mDeletePackageHelper.deletePackageLIF(ps.getPackageName(), null, false,
- userIds, deleteFlags, outInfo, false)) {
+ userIds, deleteFlags, new PackageRemovedInfo(), false)) {
unloaded.add(pkg);
} else {
Slog.w(TAG, "Failed to unload " + ps.getPath());
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index fe8c12c8e232..4e70cc52ef90 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -27,10 +27,10 @@ import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.Intent;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Bundle;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -88,8 +88,8 @@ public final class SuspendPackageHelper {
* @param dialogInfo An optional {@link SuspendDialogInfo} object describing the dialog that
* should be shown to the user when they try to launch a suspended app.
* Ignored if {@code suspended} is false.
- * @param callingPackage The caller's package name.
- * @param userId The user where packages reside.
+ * @param suspendingPackage The caller's package name.
+ * @param targetUserId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of failed packages.
*/
@@ -97,14 +97,14 @@ public final class SuspendPackageHelper {
String[] setPackagesSuspended(@NonNull Computer snapshot, @Nullable String[] packageNames,
boolean suspended, @Nullable PersistableBundle appExtras,
@Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
- @NonNull String callingPackage, @UserIdInt int userId, int callingUid,
+ @NonNull UserPackage suspendingPackage, @UserIdInt int targetUserId, int callingUid,
boolean quarantined) {
if (ArrayUtils.isEmpty(packageNames)) {
return packageNames;
}
- if (suspended && !quarantined && !isSuspendAllowedForUser(snapshot, userId,
- callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ if (suspended && !quarantined
+ && !isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
return packageNames;
}
@@ -119,19 +119,21 @@ public final class SuspendPackageHelper {
final IntArray changedUids = new IntArray(packageNames.length);
final boolean[] canSuspend = suspended
- ? canSuspendPackageForUser(snapshot, packageNames, userId, callingUid)
+ ? canSuspendPackageForUser(snapshot, packageNames, targetUserId, callingUid)
: null;
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
- if (callingPackage.equals(packageName)) {
- Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ if (suspendingPackage.packageName.equals(packageName)
+ && suspendingPackage.userId == targetUserId) {
+ Slog.w(TAG, "Suspending package: " + suspendingPackage + " trying to "
+ (suspended ? "" : "un") + "suspend itself. Ignoring");
unmodifiablePackages.add(packageName);
continue;
}
final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
- if (packageState == null || !packageState.getUserStateOrDefault(userId).isInstalled()
- || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ if (packageState == null
+ || !packageState.getUserStateOrDefault(targetUserId).isInstalled()
+ || snapshot.shouldFilterApplication(packageState, callingUid, targetUserId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unmodifiablePackages.add(packageName);
@@ -142,34 +144,34 @@ public final class SuspendPackageHelper {
continue;
}
- final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
- packageState.getUserStateOrDefault(userId).getSuspendParams();
+ final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
+ packageState.getUserStateOrDefault(targetUserId).getSuspendParams();
final SuspendParams oldSuspendParams = suspendParamsMap == null
- ? null : suspendParamsMap.get(callingPackage);
+ ? null : suspendParamsMap.get(suspendingPackage);
boolean changed = !Objects.equals(oldSuspendParams, newSuspendParams);
if (suspended && !changed) {
// Carried over API behavior, must notify change even if no change
notifyPackagesList.add(packageName);
notifyUids.add(
- UserHandle.getUid(userId, packageState.getAppId()));
+ UserHandle.getUid(targetUserId, packageState.getAppId()));
continue;
}
- // If only the callingPackage is suspending this package,
+ // If only the suspendingPackage is suspending this package,
// it will be unsuspended when this change is committed
boolean packageUnsuspended = !suspended
&& CollectionUtils.size(suspendParamsMap) == 1
- && suspendParamsMap.containsKey(callingPackage);
+ && suspendParamsMap.containsKey(suspendingPackage);
if (suspended || packageUnsuspended) {
// Always notify of a suspend call + notify when fully unsuspended
notifyPackagesList.add(packageName);
- notifyUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ notifyUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
}
if (changed) {
changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ changedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
} else {
Slog.w(TAG, "No change is needed for package: " + packageName
+ ". Skipping suspending/un-suspending.");
@@ -181,11 +183,11 @@ public final class SuspendPackageHelper {
for (int index = 0; index < size; index++) {
final String packageName = changedPackagesList.valueAt(index);
final PackageUserStateWrite userState = mutator.forPackage(packageName)
- .userState(userId);
+ .userState(targetUserId);
if (suspended) {
- userState.putSuspendParams(callingPackage, newSuspendParams);
+ userState.putSuspendParams(suspendingPackage, newSuspendParams);
} else {
- userState.removeSuspension(callingPackage);
+ userState.removeSuspension(suspendingPackage);
}
}
});
@@ -197,17 +199,17 @@ public final class SuspendPackageHelper {
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
- changedPackages, notifyUids.toArray(), quarantined, userId);
+ changedPackages, notifyUids.toArray(), quarantined, targetUserId);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, changedPackages,
- suspended, userId);
- mPm.scheduleWritePackageRestrictions(userId);
+ suspended, targetUserId);
+ mPm.scheduleWritePackageRestrictions(targetUserId);
}
// Send the suspension changed broadcast to ensure suspension state is not stale.
if (!changedPackagesList.isEmpty()) {
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
changedPackagesList.toArray(new String[0]), changedUids.toArray(), quarantined,
- userId);
+ targetUserId);
}
return unmodifiablePackages.toArray(new String[0]);
}
@@ -216,19 +218,19 @@ public final class SuspendPackageHelper {
* Returns the names in the {@code packageNames} which can not be suspended by the caller.
*
* @param packageNames The names of packages to check.
- * @param userId The user where packages reside.
+ * @param targetUserId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of packages which are Unsuspendable.
*/
@NonNull
String[] getUnsuspendablePackagesForUser(@NonNull Computer snapshot,
- @NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
- if (!isSuspendAllowedForUser(snapshot, userId, callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ @NonNull String[] packageNames, @UserIdInt int targetUserId, int callingUid) {
+ if (!isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
return packageNames;
}
final ArraySet<String> unactionablePackages = new ArraySet<>();
- final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, userId,
+ final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, targetUserId,
callingUid);
for (int i = 0; i < packageNames.length; i++) {
if (!canSuspend[i]) {
@@ -237,7 +239,7 @@ public final class SuspendPackageHelper {
}
final PackageStateInternal packageState =
snapshot.getPackageStateForInstalledAndFiltered(
- packageNames[i], callingUid, userId);
+ packageNames[i], callingUid, targetUserId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -285,30 +287,31 @@ public final class SuspendPackageHelper {
* @param packagesToChange The packages on which the suspension are to be removed.
* @param suspendingPackagePredicate A predicate identifying the suspending packages whose
* suspensions will be removed.
- * @param userId The user for which the changes are taking place.
+ * @param targetUserId The user for which the changes are taking place.
*/
void removeSuspensionsBySuspendingPackage(@NonNull Computer snapshot,
@NonNull String[] packagesToChange,
- @NonNull Predicate<String> suspendingPackagePredicate, int userId) {
+ @NonNull Predicate<UserPackage> suspendingPackagePredicate, int targetUserId) {
final List<String> unsuspendedPackages = new ArrayList<>();
final IntArray unsuspendedUids = new IntArray();
- final ArrayMap<String, ArraySet<String>> pkgToSuspendingPkgsToCommit = new ArrayMap<>();
+ final ArrayMap<String, ArraySet<UserPackage>> pkgToSuspendingPkgsToCommit =
+ new ArrayMap<>();
for (String packageName : packagesToChange) {
final PackageStateInternal packageState =
snapshot.getPackageStateInternal(packageName);
final PackageUserStateInternal packageUserState = packageState == null
- ? null : packageState.getUserStateOrDefault(userId);
+ ? null : packageState.getUserStateOrDefault(targetUserId);
if (packageUserState == null || !packageUserState.isSuspended()) {
continue;
}
- WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
packageUserState.getSuspendParams();
int countRemoved = 0;
for (int index = 0; index < suspendParamsMap.size(); index++) {
- String suspendingPackage = suspendParamsMap.keyAt(index);
+ UserPackage suspendingPackage = suspendParamsMap.keyAt(index);
if (suspendingPackagePredicate.test(suspendingPackage)) {
- ArraySet<String> suspendingPkgsToCommit =
+ ArraySet<UserPackage> suspendingPkgsToCommit =
pkgToSuspendingPkgsToCommit.get(packageName);
if (suspendingPkgsToCommit == null) {
suspendingPkgsToCommit = new ArraySet<>();
@@ -322,31 +325,33 @@ public final class SuspendPackageHelper {
// Everything would be removed and package unsuspended
if (countRemoved == suspendParamsMap.size()) {
unsuspendedPackages.add(packageState.getPackageName());
- unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ unsuspendedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
}
}
mPm.commitPackageStateMutation(null, mutator -> {
for (int mapIndex = 0; mapIndex < pkgToSuspendingPkgsToCommit.size(); mapIndex++) {
String packageName = pkgToSuspendingPkgsToCommit.keyAt(mapIndex);
- ArraySet<String> packagesToRemove = pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
- PackageUserStateWrite userState = mutator.forPackage(packageName).userState(userId);
+ ArraySet<UserPackage> packagesToRemove =
+ pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
+ PackageUserStateWrite userState =
+ mutator.forPackage(packageName).userState(targetUserId);
for (int setIndex = 0; setIndex < packagesToRemove.size(); setIndex++) {
userState.removeSuspension(packagesToRemove.valueAt(setIndex));
}
}
});
- mPm.scheduleWritePackageRestrictions(userId);
+ mPm.scheduleWritePackageRestrictions(targetUserId);
final Computer newSnapshot = mPm.snapshotComputer();
if (!unsuspendedPackages.isEmpty()) {
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, packageArray,
- false, userId);
+ false, targetUserId);
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_UNSUSPENDED,
- packageArray, unsuspendedUids.toArray(), false, userId);
+ packageArray, unsuspendedUids.toArray(), false, targetUserId);
}
}
@@ -404,7 +409,7 @@ public final class SuspendPackageHelper {
* @return The name of suspending package.
*/
@Nullable
- String getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
+ UserPackage getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
int userId, int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -417,12 +422,25 @@ public final class SuspendPackageHelper {
return null;
}
- String suspendingPackage = null;
+ UserPackage suspendingPackage = null;
+ UserPackage suspendedBySystem = null;
+ UserPackage qasPackage = null;
for (int i = 0; i < userState.getSuspendParams().size(); i++) {
suspendingPackage = userState.getSuspendParams().keyAt(i);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
- return suspendingPackage;
+ var suspendParams = userState.getSuspendParams().valueAt(i);
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
+ suspendedBySystem = suspendingPackage;
}
+ if (suspendParams.isQuarantined() && qasPackage == null) {
+ qasPackage = suspendingPackage;
+ }
+ }
+ // Precedence: quarantined, then system, then suspending.
+ if (qasPackage != null) {
+ return qasPackage;
+ }
+ if (suspendedBySystem != null) {
+ return suspendedBySystem;
}
return suspendingPackage;
}
@@ -438,7 +456,7 @@ public final class SuspendPackageHelper {
*/
@Nullable
SuspendDialogInfo getSuspendedDialogInfo(@NonNull Computer snapshot,
- @NonNull String suspendedPackage, @NonNull String suspendingPackage, int userId,
+ @NonNull String suspendedPackage, @NonNull UserPackage suspendingPackage, int userId,
int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -451,7 +469,7 @@ public final class SuspendPackageHelper {
return null;
}
- final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
userState.getSuspendParams();
if (suspendParamsMap == null) {
return null;
@@ -480,34 +498,36 @@ public final class SuspendPackageHelper {
* be suspended or not.
*
* @param packageNames The package names to check suspendability for.
- * @param userId The user to check in
+ * @param targetUserId The user to check in
* @param callingUid The caller's uid.
* @return An array containing results of the checks
*/
@NonNull
boolean[] canSuspendPackageForUser(@NonNull Computer snapshot, @NonNull String[] packageNames,
- int userId, int callingUid) {
+ int targetUserId, int callingUid) {
final boolean[] canSuspend = new boolean[packageNames.length];
- final boolean isCallerOwner = isCallerDeviceOrProfileOwner(snapshot, userId, callingUid);
+ final boolean isCallerOwner =
+ isCallerDeviceOrProfileOwner(snapshot, targetUserId, callingUid);
final long token = Binder.clearCallingIdentity();
try {
final DefaultAppProvider defaultAppProvider = mInjector.getDefaultAppProvider();
- final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId);
- final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId);
+ final String activeLauncherPackageName =
+ defaultAppProvider.getDefaultHome(targetUserId);
+ final String dialerPackageName = defaultAppProvider.getDefaultDialer(targetUserId);
final String requiredInstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, targetUserId);
final String requiredUninstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, targetUserId);
final String requiredVerifierPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, targetUserId);
final String requiredPermissionControllerPackage =
getKnownPackageName(snapshot, KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
- userId);
+ targetUserId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
- if (mPm.isPackageDeviceAdmin(packageName, userId)) {
+ if (mPm.isPackageDeviceAdmin(packageName, targetUserId)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": has an active device admin");
continue;
@@ -542,12 +562,12 @@ public final class SuspendPackageHelper {
+ "\": required for permissions management");
continue;
}
- if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ if (mProtectedPackages.isPackageStateProtected(targetUserId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": protected package");
continue;
}
- if (!isCallerOwner && snapshot.getBlockUninstall(userId, packageName)) {
+ if (!isCallerOwner && snapshot.getBlockUninstall(targetUserId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": blocked by admin");
continue;
@@ -559,7 +579,7 @@ public final class SuspendPackageHelper {
PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (pkg != null) {
- final int uid = UserHandle.getUid(userId, packageState.getAppId());
+ final int uid = UserHandle.getUid(targetUserId, packageState.getAppId());
// Cannot suspend SDK libs as they are controlled by SDK manager.
if (pkg.isSdkLibrary()) {
Slog.w(TAG, "Cannot suspend package: " + packageName
@@ -601,20 +621,6 @@ public final class SuspendPackageHelper {
== AppOpsManager.MODE_ALLOWED;
}
- /**
- * Suspends packages on behalf of an admin.
- *
- * @return array of packages that are unsuspendable, either because admin is not allowed to
- * suspend them (e.g. current dialer) or there was other problem (e.g. package not found).
- */
- public String[] setPackagesSuspendedByAdmin(
- Computer snapshot, int userId, String[] packageNames, boolean suspend) {
- return setPackagesSuspended(snapshot, packageNames, suspend,
- null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */,
- PackageManagerService.PLATFORM_PACKAGE_NAME, userId, Process.SYSTEM_UID,
- false /* quarantined */);
- }
-
private String getKnownPackageName(@NonNull Computer snapshot,
@KnownPackages.KnownPackage int knownPackage, int userId) {
final String[] knownPackages =
@@ -622,14 +628,15 @@ public final class SuspendPackageHelper {
return knownPackages.length > 0 ? knownPackages[0] : null;
}
- private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int userId,
+ private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int targetUserId,
int callingUid) {
if (callingUid == SYSTEM_UID) {
return true;
}
- final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ final String ownerPackage =
+ mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
if (ownerPackage != null) {
- return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, userId,
+ return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, targetUserId,
callingUid);
}
return false;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a7b52f4e7a58..c48eccf2aac5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -532,9 +532,10 @@ public class UserManagerService extends IUserManager.Stub {
}
final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class);
final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
+ final String callingPackage = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
// Call setQuietModeEnabled on bg thread to avoid ANR
BackgroundThread.getHandler().post(() ->
- setQuietModeEnabled(userId, false, target, /* callingPackage */ null));
+ setQuietModeEnabled(userId, false, target, callingPackage));
}
};
@@ -1410,7 +1411,7 @@ public class UserManagerService extends IUserManager.Stub {
if (onlyIfCredentialNotRequired) {
return false;
}
- showConfirmCredentialToDisableQuietMode(userId, target);
+ showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
return false;
}
}
@@ -1434,7 +1435,7 @@ public class UserManagerService extends IUserManager.Stub {
if (onlyIfCredentialNotRequired) {
return false;
}
- showConfirmCredentialToDisableQuietMode(userId, target);
+ showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
return false;
}
setQuietModeEnabled(userId, false /* enableQuietMode */, target, callingPackage);
@@ -1604,7 +1605,7 @@ public class UserManagerService extends IUserManager.Stub {
* Show confirm credential screen to unlock user in order to turn off quiet mode.
*/
private void showConfirmCredentialToDisableQuietMode(
- @UserIdInt int userId, @Nullable IntentSender target) {
+ @UserIdInt int userId, @Nullable IntentSender target, @Nullable String callingPackage) {
if (android.app.admin.flags.Flags.quietModeCredentialBugFix()) {
// TODO (b/308121702) It may be brittle to rely on user states to check profile state
int state;
@@ -1635,6 +1636,7 @@ public class UserManagerService extends IUserManager.Stub {
}
callBackIntent.putExtra(Intent.EXTRA_USER_ID, userId);
callBackIntent.setPackage(mContext.getPackageName());
+ callBackIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackage);
callBackIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext,
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 7386301bdd6e..14db70e5f72e 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -306,7 +306,6 @@ public final class UserTypeFactory {
.setDarkThemeBadgeColors(
R.color.white)
.setDefaultRestrictions(getDefaultProfileRestrictions())
- .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
.setDefaultUserProperties(new UserProperties.Builder()
.setStartWithParent(true)
.setCredentialShareableWithParent(true)
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 459e2cf7f5c0..79c9c8ec8b0b 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -28,9 +28,9 @@ import android.system.StructStat;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.ApexManager;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import libcore.io.IoUtils;
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 b23dbee5e973..d0fe9647618a 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -28,6 +28,7 @@ import android.content.pm.ConfigurationInfo;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
@@ -52,6 +53,9 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.pkg.component.ComponentParseUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedAttribution;
import com.android.internal.pm.pkg.component.ParsedComponent;
@@ -63,11 +67,12 @@ import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import com.android.server.pm.PackageArchiver;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUnserialized;
@@ -75,9 +80,6 @@ import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.component.ComponentParseUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.io.File;
import java.util.ArrayList;
@@ -273,8 +275,8 @@ public class PackageInfoUtils {
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final ParsedActivity a = pkg.getActivities().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a,
- aflags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ a.isEnabled(), a.isDirectBootAware(), a.getName(), aflags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
a.getName())) {
continue;
@@ -293,8 +295,8 @@ public class PackageInfoUtils {
final ActivityInfo[] res = new ActivityInfo[size];
for (int i = 0; i < size; i++) {
final ParsedActivity a = pkg.getReceivers().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ a.isEnabled(), a.isDirectBootAware(), a.getName(), flags)) {
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -309,8 +311,8 @@ public class PackageInfoUtils {
final ServiceInfo[] res = new ServiceInfo[size];
for (int i = 0; i < size; i++) {
final ParsedService s = pkg.getServices().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), s,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ s.isEnabled(), s.isDirectBootAware(), s.getName(), flags)) {
res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -326,8 +328,8 @@ public class PackageInfoUtils {
for (int i = 0; i < size; i++) {
final ParsedProvider pr = pkg.getProviders()
.get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), pr,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ pr.isEnabled(), pr.isDirectBootAware(), pr.getName(), flags)) {
res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -473,7 +475,34 @@ public class PackageInfoUtils {
}
info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
? null : usesLibraryFiles.toArray(new String[0]);
- info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+
+
+ if (!Flags.sdkLibIndependence()) {
+ info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+ info.optionalSharedLibraryInfos = null;
+ } else {
+ // sharedLibraryInfos contains all shared libraries that the app depends on (including
+ // the optional sdk libraries)
+ info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+ String[] libsNames = pkgSetting.getUsesSdkLibraries();
+ boolean[] libsOptional = pkgSetting.getUsesSdkLibrariesOptional();
+ List<SharedLibraryInfo> optionalSdkLibraries = null;
+ if (!ArrayUtils.isEmpty(libsOptional) && !ArrayUtils.isEmpty(libsNames)
+ && libsNames.length == libsOptional.length) {
+ for (SharedLibraryInfo info1 : usesLibraryInfos) {
+ if (info1.getType() == SharedLibraryInfo.TYPE_SDK_PACKAGE) {
+ int index = ArrayUtils.indexOf(libsNames, info1.getName());
+ if (index >= 0 && libsOptional[index]) {
+ if (optionalSdkLibraries == null) {
+ optionalSdkLibraries = new ArrayList<>();
+ }
+ optionalSdkLibraries.add(info1);
+ }
+ }
+ }
+ }
+ info.optionalSharedLibraryInfos = optionalSdkLibraries;
+ }
if (info.category == ApplicationInfo.CATEGORY_UNDEFINED) {
info.category = pkgSetting.getCategoryOverride();
}
@@ -923,7 +952,7 @@ public class PackageInfoUtils {
| flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
| flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
| flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
- | flag(AndroidPackageUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
+ | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
| flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
return appInfoFlags(pkgWithoutStateFlags, pkgSetting);
@@ -964,12 +993,12 @@ public class PackageInfoUtils {
| flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
| flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
| flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
- | flag(AndroidPackageUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
- | flag(AndroidPackageUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
- | flag(AndroidPackageUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
- | flag(AndroidPackageUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
- | flag(AndroidPackageUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
- | flag(AndroidPackageUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
+ | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+ | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
+ | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+ | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
| flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
Boolean resizeableActivity = pkg.getResizeableActivity();
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 1c751e07bbbe..b6a08a5a546f 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -35,17 +35,19 @@ import android.util.DisplayMetrics;
import android.util.Slog;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.io.File;
import java.util.List;
+import java.util.Set;
/**
* The v2 of package parsing for use when parsing is initiated in the server and must
@@ -88,6 +90,16 @@ public class PackageParser2 implements AutoCloseable {
// behavior.
return false;
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
});
}
@@ -221,7 +233,7 @@ public class PackageParser2 implements AutoCloseable {
@NonNull String baseCodePath, @NonNull String codePath,
@NonNull TypedArray manifestArray, boolean isCoreApp) {
return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
- isCoreApp);
+ isCoreApp, Callback.this);
}
/**
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 61be6e1036f2..1b7c7ad94dc9 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -29,7 +29,9 @@ import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.incremental.IncrementalManager;
import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.pm.parsing.PackageParserException;
import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedProvider;
@@ -37,7 +39,6 @@ import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
-import com.android.server.pm.PackageManagerException;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -134,10 +135,10 @@ public class AndroidPackageUtils {
/**
* Validate the dex metadata files installed for the given package.
*
- * @throws PackageManagerException in case of errors.
+ * @throws PackageParserException in case of errors.
*/
public static void validatePackageDexMetadata(AndroidPackage pkg)
- throws PackageManagerException {
+ throws PackageParserException {
Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
String packageName = pkg.getPackageName();
long versionCode = pkg.getLongVersionCode();
@@ -146,7 +147,7 @@ public class AndroidPackageUtils {
final ParseResult result = DexMetadataHelper.validateDexMetadataFile(
input.reset(), dexMetadata, packageName, versionCode);
if (result.isError()) {
- throw new PackageManagerException(
+ throw new PackageParserException(
result.getErrorCode(), result.getErrorMessage(), result.getException());
}
}
@@ -314,60 +315,4 @@ public class AndroidPackageUtils {
info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
}
-
- /**
- * @deprecated Use {@link PackageState#isSystem}
- */
- @Deprecated
- public static boolean isSystem(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isSystem();
- }
-
- /**
- * @deprecated Use {@link PackageState#isSystemExt}
- */
- @Deprecated
- public static boolean isSystemExt(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isSystemExt();
- }
-
- /**
- * @deprecated Use {@link PackageState#isPrivileged}
- */
- @Deprecated
- public static boolean isPrivileged(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isPrivileged();
- }
-
- /**
- * @deprecated Use {@link PackageState#isOem}
- */
- @Deprecated
- public static boolean isOem(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isOem();
- }
-
- /**
- * @deprecated Use {@link PackageState#isVendor}
- */
- @Deprecated
- public static boolean isVendor(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isVendor();
- }
-
- /**
- * @deprecated Use {@link PackageState#isProduct}
- */
- @Deprecated
- public static boolean isProduct(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isProduct();
- }
-
- /**
- * @deprecated Use {@link PackageState#isOdm}
- */
- @Deprecated
- public static boolean isOdm(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isOdm();
- }
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 8bd2d94667f9..671e031b546b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -120,8 +120,11 @@ import com.android.internal.compat.IPlatformCompat;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.RoSystemProperties;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.IntPair;
@@ -144,8 +147,6 @@ import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 2f4ad2d8fcc6..15b693cf72f8 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
import android.util.Pair;
@@ -173,7 +174,7 @@ class PackageUserStateDefault implements PackageUserStateInternal {
@Nullable
@Override
- public WatchedArrayMap<String, SuspendParams> getSuspendParams() {
+ public WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams() {
return null;
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index c5ef5257ddd5..7a5a14d8d3c2 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -121,7 +122,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@Nullable
- private WatchedArrayMap<String, SuspendParams> mSuspendParams;
+ private WatchedArrayMap<UserPackage, SuspendParams> mSuspendParams;
@Nullable
private WatchedArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
@@ -369,7 +370,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
return !CollectionUtils.isEmpty(mSuspendParams);
}
- public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
+ /**
+ * Adds or updates suspension params by the given package.
+ */
+ public PackageUserStateImpl putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mSuspendParams == null) {
mSuspendParams = new WatchedArrayMap<>();
@@ -384,7 +388,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
return this;
}
- public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) {
+ /**
+ * Removes suspension by the given package.
+ */
+ public PackageUserStateImpl removeSuspension(@NonNull UserPackage suspendingPackage) {
if (mSuspendParams != null) {
mSuspendParams.remove(suspendingPackage);
onChanged();
@@ -565,7 +572,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
public @NonNull PackageUserStateImpl setSuspendParams(
- @NonNull ArrayMap<String, SuspendParams> value) {
+ @NonNull ArrayMap<UserPackage, SuspendParams> value) {
if (value == null) {
return this;
}
@@ -778,7 +785,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @Nullable WatchedArrayMap<String,SuspendParams> getSuspendParams() {
+ public @Nullable WatchedArrayMap<UserPackage,SuspendParams> getSuspendParams() {
return mSuspendParams;
}
@@ -830,7 +837,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<String,SuspendParams> value) {
+ public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<UserPackage,SuspendParams> value) {
mSuspendParams = value;
return this;
}
@@ -909,10 +916,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
@DataClass.Generated(
- time = 1701470095849L,
+ time = 1701864813354L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(android.content.pm.UserPackage)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
index 46cc830130ef..f8d745cb7fbf 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
@@ -19,6 +19,7 @@ package com.android.server.pm.pkg;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.pm.UserPackage;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.util.Pair;
@@ -38,7 +39,7 @@ public interface PackageUserStateInternal extends PackageUserState, FrameworkPac
// TODO: Make non-null with emptyMap()
@Nullable
- WatchedArrayMap<String, SuspendParams> getSuspendParams();
+ WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams();
@Nullable
WatchedArraySet<String> getDisabledComponentsNoCopy();
diff --git a/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
index 6cbc1de75010..6a156415982c 100644
--- a/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
+++ b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
@@ -16,6 +16,8 @@
package com.android.server.pm.pkg;
+import com.android.internal.pm.pkg.SEInfoUtil;
+
/**
* Utility methods that need to be used in application space.
* @hide
@@ -23,10 +25,10 @@ package com.android.server.pm.pkg;
public final class SELinuxUtil {
/** Append to existing seinfo label for instant apps @hide */
- private static final String INSTANT_APP_STR = ":ephemeralapp";
+ private static final String INSTANT_APP_STR = SEInfoUtil.INSTANT_APP_STR;
/** Append to existing seinfo when modifications are complete @hide */
- public static final String COMPLETE_STR = ":complete";
+ public static final String COMPLETE_STR = SEInfoUtil.COMPLETE_STR;
/** @hide */
public static String getSeinfoUser(PackageUserState userState) {
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
index 8430cf7a0d11..253eb4006122 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
@@ -349,7 +350,7 @@ public class PackageStateMutator {
@NonNull
@Override
- public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ public PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mUserState != null) {
mUserState.putSuspendParams(suspendingPackage, suspendParams);
@@ -359,7 +360,7 @@ public class PackageStateMutator {
@NonNull
@Override
- public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) {
+ public PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage) {
if (mUserState != null) {
mUserState.removeSuspension(suspendingPackage);
}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
index 0c6c6723b79b..f6b21045a8bb 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import com.android.server.pm.pkg.PackageUserStateImpl;
@@ -38,11 +39,11 @@ public interface PackageUserStateWrite {
@PackageManager.DistractionRestriction int restrictionFlags);
@NonNull
- PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams);
@NonNull
- PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage);
+ PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage);
@NonNull
PackageUserStateWrite setHidden(boolean hidden);
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 532a7f8f893f..c9da99da7902 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -45,11 +45,13 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.util.ArrayUtils;
import com.android.server.IntentResolver;
@@ -62,8 +64,6 @@ import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
import com.android.server.pm.snapshot.PackageDataSnapshot;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4e5dc1dd76fa..938ed2329ffd 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -76,7 +76,6 @@ import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
-import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -97,7 +96,6 @@ import static com.android.server.wm.WindowManagerPolicyProto.SCREEN_ON_FULLY;
import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE;
import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -124,7 +122,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -204,8 +201,6 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
-import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
-import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.display.BrightnessUtils;
@@ -385,8 +380,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public static final String TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD = "waitForAllWindowsDrawn";
- private static final String TALKBACK_LABEL = "TalkBack";
-
private static final int POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS = 800;
/**
@@ -477,6 +470,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** Controller that supports enabling an AccessibilityService by holding down the volume keys */
private AccessibilityShortcutController mAccessibilityShortcutController;
+ private TalkbackShortcutController mTalkbackShortcutController;
+
boolean mSafeMode;
// Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
@@ -813,7 +808,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
handleScreenShot(msg.arg1);
break;
case MSG_SWITCH_KEYBOARD_LAYOUT:
- handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
+ SwitchKeyboardLayoutMessageObject object =
+ (SwitchKeyboardLayoutMessageObject) msg.obj;
+ handleSwitchKeyboardLayout(object.keyEvent, object.direction,
+ object.focusedToken);
break;
case MSG_LOG_KEYBOARD_SYSTEM_EVENT:
handleKeyboardSystemEvent(KeyboardLogEvent.from(msg.arg1), (KeyEvent) msg.obj);
@@ -934,6 +932,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private record SwitchKeyboardLayoutMessageObject(KeyEvent keyEvent, IBinder focusedToken,
+ int direction) {
+ }
+
final IPersistentVrStateCallbacks mPersistentVrModeListener =
new IPersistentVrStateCallbacks.Stub() {
@Override
@@ -1602,19 +1604,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (DEBUG_INPUT) {
Slog.d(TAG, "Executing stem primary triple press action behavior.");
}
-
- if (Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
- /* def= */ 0, UserHandle.USER_CURRENT) == 1) {
- /** Toggle talkback begin */
- ComponentName componentName = getTalkbackComponent();
- if (componentName != null && toggleTalkBack(componentName)) {
- /** log stem triple press telemetry if it's a talkback enabled event */
- logStemTriplePressAccessibilityTelemetry(componentName);
- }
- performHapticFeedback(HapticFeedbackConstants.CONFIRM, /* always = */ false,
- /* reason = */ "Stem primary - Triple Press - Toggle Accessibility");
- /** Toggle talkback end */
+ mTalkbackShortcutController.toggleTalkback(mCurrentUserId);
+ if (mTalkbackShortcutController.isTalkBackShortcutGestureEnabled()) {
+ performHapticFeedback(HapticFeedbackConstants.CONFIRM, /* always = */
+ false, /* reason = */
+ "Stem primary - Triple Press - Toggle Accessibility");
}
break;
}
@@ -1640,61 +1634,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/**
- * A function that toggles talkback service
- *
- * @return {@code true} if talkback is enabled, {@code false} if talkback is disabled
- */
- private boolean toggleTalkBack(ComponentName componentName) {
- final Set<ComponentName> enabledServices =
- AccessibilityUtils.getEnabledServicesFromSettings(mContext, mCurrentUserId);
-
- boolean isTalkbackAlreadyEnabled = enabledServices.contains(componentName);
- AccessibilityUtils.setAccessibilityServiceState(mContext, componentName,
- !isTalkbackAlreadyEnabled);
- /** if isTalkbackAlreadyEnabled is true, then it's a disabled event so return false
- * and if isTalkbackAlreadyEnabled is false, return true as it's an enabled event */
- return !isTalkbackAlreadyEnabled;
- }
-
- /**
- * A function that logs stem triple press accessibility telemetry
- * If the user setup (Oobe) is not completed, set the
- * WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE
- * setting which will be later logged via Settings Snapshot
- * else, log ACCESSIBILITY_SHORTCUT_REPORTED atom
- */
- private void logStemTriplePressAccessibilityTelemetry(ComponentName componentName) {
- if (!AccessibilityUtils.isUserSetupCompleted(mContext)) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, 1);
- } else {
- AccessibilityStatsLogUtils.logAccessibilityShortcutActivated(mContext, componentName,
- ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE,
- /* serviceEnabled= */ true);
- }
- }
-
- private ComponentName getTalkbackComponent() {
- AccessibilityManager accessibilityManager = mContext.getSystemService(
- AccessibilityManager.class);
- List<AccessibilityServiceInfo> serviceInfos =
- accessibilityManager.getInstalledAccessibilityServiceList();
-
- for (AccessibilityServiceInfo service : serviceInfos) {
- final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
- if (isTalkback(serviceInfo)) {
- return new ComponentName(serviceInfo.packageName, serviceInfo.name);
- }
- }
- return null;
- }
-
- private boolean isTalkback(ServiceInfo info) {
- String label = info.loadLabel(mPackageManager).toString();
- return label.equals(TALKBACK_LABEL);
- }
-
- /**
* Load most recent task (expect current task) and bring it to the front.
*/
void performStemPrimaryDoublePressSwitchToRecentTask() {
@@ -1731,12 +1670,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TRIPLE_PRESS_PRIMARY_NOTHING:
break;
case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY:
- if (Settings.System.getIntForUser(
- mContext.getContentResolver(),
- Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
- /* def= */ 0,
- UserHandle.USER_CURRENT)
- == 1) {
+ if (mTalkbackShortcutController.isTalkBackShortcutGestureEnabled()) {
return 3;
}
break;
@@ -2252,6 +2186,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
ButtonOverridePermissionChecker getButtonOverridePermissionChecker() {
return new ButtonOverridePermissionChecker();
}
+
+ TalkbackShortcutController getTalkbackShortcutController() {
+ return new TalkbackShortcutController(mContext);
+ }
}
/** {@inheritDoc} */
@@ -2515,6 +2453,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDrawnTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_keyguardDrawnTimeout);
mKeyguardDelegate = injector.getKeyguardServiceDelegate();
+ mTalkbackShortcutController = injector.getTalkbackShortcutController();
initKeyCombinationRules();
initSingleKeyGestureRules(injector.getLooper());
mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker();
@@ -3709,7 +3648,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
if (firstDown) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
- sendSwitchKeyboardLayout(event, direction);
+ sendSwitchKeyboardLayout(event, focusedToken, direction);
logKeyboardSystemsEvent(event, KeyboardLogEvent.LANGUAGE_SWITCH);
return true;
}
@@ -3978,7 +3917,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ ", policyFlags=" + policyFlags);
}
- if (interceptUnhandledKey(event)) {
+ if (interceptUnhandledKey(event, focusedToken)) {
return null;
}
@@ -4036,7 +3975,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return fallbackEvent;
}
- private boolean interceptUnhandledKey(KeyEvent event) {
+ private boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) {
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
@@ -4049,7 +3988,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (KeyEvent.metaStateHasModifiers(metaState & ~KeyEvent.META_SHIFT_MASK,
KeyEvent.META_CTRL_ON)) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
- sendSwitchKeyboardLayout(event, direction);
+ sendSwitchKeyboardLayout(event, focusedToken, direction);
return true;
}
}
@@ -4105,16 +4044,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private void sendSwitchKeyboardLayout(@NonNull KeyEvent event, int direction) {
- mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, event.getDeviceId(),
- direction).sendToTarget();
+ private void sendSwitchKeyboardLayout(@NonNull KeyEvent event,
+ @Nullable IBinder focusedToken, int direction) {
+ SwitchKeyboardLayoutMessageObject object =
+ new SwitchKeyboardLayoutMessageObject(event, focusedToken, direction);
+ mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, object).sendToTarget();
}
- private void handleSwitchKeyboardLayout(int deviceId, int direction) {
+ private void handleSwitchKeyboardLayout(@NonNull KeyEvent event, int direction,
+ IBinder focusedToken) {
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
- InputMethodManagerInternal.get().switchKeyboardLayout(direction);
+ IBinder targetWindowToken =
+ mWindowManagerInternal.getTargetWindowTokenFromInputToken(focusedToken);
+ InputMethodManagerInternal.get().onSwitchKeyboardLayoutShortcut(direction,
+ event.getDisplayId(), targetWindowToken);
} else {
- mWindowManagerFuncs.switchKeyboardLayout(deviceId, direction);
+ mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
}
}
@@ -4124,7 +4069,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
focusedToken, fallbackEvent, policyFlags);
- if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent)) {
+ if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent, focusedToken)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/policy/TalkbackShortcutController.java b/services/core/java/com/android/server/policy/TalkbackShortcutController.java
new file mode 100644
index 000000000000..906da2f4cdf5
--- /dev/null
+++ b/services/core/java/com/android/server/policy/TalkbackShortcutController.java
@@ -0,0 +1,118 @@
+/*
+ * 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.policy;
+
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
+import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class controls talkback shortcut related operations such as toggling, quering and
+ * logging.
+ */
+@VisibleForTesting
+class TalkbackShortcutController {
+ private static final String TALKBACK_LABEL = "TalkBack";
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ TalkbackShortcutController(Context context) {
+ mContext = context;
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ /**
+ * A function that toggles talkback service.
+ *
+ * @return talkback state after toggle. {@code true} if talkback is enabled, {@code false} if
+ * talkback is disabled
+ */
+ boolean toggleTalkback(int userId) {
+ final Set<ComponentName> enabledServices =
+ AccessibilityUtils.getEnabledServicesFromSettings(mContext, userId);
+ ComponentName componentName = getTalkbackComponent();
+ boolean isTalkbackAlreadyEnabled = enabledServices.contains(componentName);
+
+ if (isTalkBackShortcutGestureEnabled()) {
+ isTalkbackAlreadyEnabled = !isTalkbackAlreadyEnabled;
+ AccessibilityUtils.setAccessibilityServiceState(mContext, componentName,
+ isTalkbackAlreadyEnabled);
+
+ // log stem triple press telemetry if it's a talkback enabled event.
+ if (componentName != null && isTalkbackAlreadyEnabled) {
+ logStemTriplePressAccessibilityTelemetry(componentName);
+ }
+ }
+ return isTalkbackAlreadyEnabled;
+ }
+
+ private ComponentName getTalkbackComponent() {
+ AccessibilityManager accessibilityManager = mContext.getSystemService(
+ AccessibilityManager.class);
+ List<AccessibilityServiceInfo> serviceInfos =
+ accessibilityManager.getInstalledAccessibilityServiceList();
+
+ for (AccessibilityServiceInfo service : serviceInfos) {
+ final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
+ if (isTalkback(serviceInfo)) {
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ }
+ }
+ return null;
+ }
+
+ boolean isTalkBackShortcutGestureEnabled() {
+ return Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED,
+ /* def= */ 0, UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
+ * A function that logs stem triple press accessibility telemetry. If the user setup (Oobe)
+ * is not completed, set the WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE setting which
+ * will be later logged via Settings Snapshot else, log ACCESSIBILITY_SHORTCUT_REPORTED atom
+ */
+ private void logStemTriplePressAccessibilityTelemetry(ComponentName componentName) {
+ if (!AccessibilityUtils.isUserSetupCompleted(mContext)) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, 1);
+ return;
+ }
+ AccessibilityStatsLogUtils.logAccessibilityShortcutActivated(mContext,
+ componentName,
+ ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE,
+ /* serviceEnabled= */ true);
+ }
+
+ private boolean isTalkback(ServiceInfo info) {
+ return TALKBACK_LABEL.equals(info.loadLabel(mPackageManager).toString());
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
index abfe9debc7de..e1eb8f07dd2c 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
@@ -20,7 +20,6 @@ import android.annotation.Nullable;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.PersistableBundle;
-import android.util.FastImmutableArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -30,8 +29,9 @@ import com.android.internal.os.PowerStats;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.function.Consumer;
-import java.util.stream.Stream;
/**
* Collects snapshots of power-related system statistics.
@@ -246,8 +246,7 @@ public abstract class PowerStatsCollector {
@GuardedBy("this")
@SuppressWarnings("unchecked")
- private volatile FastImmutableArraySet<Consumer<PowerStats>> mConsumerList =
- new FastImmutableArraySet<Consumer<PowerStats>>(new Consumer[0]);
+ private volatile List<Consumer<PowerStats>> mConsumerList = Collections.emptyList();
public PowerStatsCollector(Handler handler, long throttlePeriodMs, Clock clock) {
mHandler = handler;
@@ -262,9 +261,13 @@ public abstract class PowerStatsCollector {
@SuppressWarnings("unchecked")
public void addConsumer(Consumer<PowerStats> consumer) {
synchronized (this) {
- mConsumerList = new FastImmutableArraySet<Consumer<PowerStats>>(
- Stream.concat(mConsumerList.stream(), Stream.of(consumer))
- .toArray(Consumer[]::new));
+ if (mConsumerList.contains(consumer)) {
+ return;
+ }
+
+ List<Consumer<PowerStats>> newList = new ArrayList<>(mConsumerList);
+ newList.add(consumer);
+ mConsumerList = Collections.unmodifiableList(newList);
}
}
@@ -275,9 +278,9 @@ public abstract class PowerStatsCollector {
@SuppressWarnings("unchecked")
public void removeConsumer(Consumer<PowerStats> consumer) {
synchronized (this) {
- mConsumerList = new FastImmutableArraySet<Consumer<PowerStats>>(
- mConsumerList.stream().filter(c -> c != consumer)
- .toArray(Consumer[]::new));
+ List<Consumer<PowerStats>> newList = new ArrayList<>(mConsumerList);
+ newList.remove(consumer);
+ mConsumerList = Collections.unmodifiableList(newList);
}
}
@@ -302,8 +305,9 @@ public abstract class PowerStatsCollector {
if (stats == null) {
return;
}
- for (Consumer<PowerStats> consumer : mConsumerList) {
- consumer.accept(stats);
+ List<Consumer<PowerStats>> consumerList = mConsumerList;
+ for (int i = consumerList.size() - 1; i >= 0; i--) {
+ consumerList.get(i).accept(stats);
}
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java b/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java
index 97d872a1a539..121a98bab37a 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsScheduler.java
@@ -18,7 +18,6 @@ package com.android.server.power.stats;
import android.annotation.DurationMillisLong;
import android.app.AlarmManager;
-import android.content.Context;
import android.os.ConditionVariable;
import android.os.Handler;
import android.util.IndentingPrintWriter;
@@ -30,6 +29,7 @@ import com.android.internal.os.MonotonicClock;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
/**
* Controls the frequency at which {@link PowerStatsSpan}'s are generated and stored in
@@ -39,7 +39,7 @@ public class PowerStatsScheduler {
private static final long MINUTE_IN_MILLIS = TimeUnit.MINUTES.toMillis(1);
private static final long HOUR_IN_MILLIS = TimeUnit.HOURS.toMillis(1);
- private final Context mContext;
+ private final AlarmScheduler mAlarmScheduler;
private boolean mEnablePeriodicPowerStatsCollection;
@DurationMillisLong
private final long mAggregatedPowerStatsSpanDuration;
@@ -49,24 +49,38 @@ public class PowerStatsScheduler {
private final Clock mClock;
private final MonotonicClock mMonotonicClock;
private final Handler mHandler;
- private final BatteryStatsImpl mBatteryStats;
+ private final Runnable mPowerStatsCollector;
+ private final Supplier<Long> mEarliestAvailableBatteryHistoryTimeMs;
private final PowerStatsAggregator mPowerStatsAggregator;
private long mLastSavedSpanEndMonotonicTime;
- public PowerStatsScheduler(Context context, PowerStatsAggregator powerStatsAggregator,
+ /**
+ * External dependency on AlarmManager.
+ */
+ public interface AlarmScheduler {
+ /**
+ * Should use AlarmManager to schedule an inexact, non-wakeup alarm.
+ */
+ void scheduleAlarm(long triggerAtMillis, String tag,
+ AlarmManager.OnAlarmListener onAlarmListener, Handler handler);
+ }
+
+ public PowerStatsScheduler(Runnable powerStatsCollector,
+ PowerStatsAggregator powerStatsAggregator,
@DurationMillisLong long aggregatedPowerStatsSpanDuration,
@DurationMillisLong long powerStatsAggregationPeriod, PowerStatsStore powerStatsStore,
- Clock clock, MonotonicClock monotonicClock, Handler handler,
- BatteryStatsImpl batteryStats) {
- mContext = context;
+ AlarmScheduler alarmScheduler, Clock clock, MonotonicClock monotonicClock,
+ Supplier<Long> earliestAvailableBatteryHistoryTimeMs, Handler handler) {
mPowerStatsAggregator = powerStatsAggregator;
mAggregatedPowerStatsSpanDuration = aggregatedPowerStatsSpanDuration;
mPowerStatsAggregationPeriod = powerStatsAggregationPeriod;
mPowerStatsStore = powerStatsStore;
+ mAlarmScheduler = alarmScheduler;
mClock = clock;
mMonotonicClock = monotonicClock;
mHandler = handler;
- mBatteryStats = batteryStats;
+ mPowerStatsCollector = powerStatsCollector;
+ mEarliestAvailableBatteryHistoryTimeMs = earliestAvailableBatteryHistoryTimeMs;
}
/**
@@ -81,9 +95,8 @@ public class PowerStatsScheduler {
}
private void scheduleNextPowerStatsAggregation() {
- AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
- alarmManager.set(AlarmManager.ELAPSED_REALTIME,
- mClock.elapsedRealtime() + mPowerStatsAggregationPeriod, "PowerStats",
+ mAlarmScheduler.scheduleAlarm(mClock.elapsedRealtime() + mPowerStatsAggregationPeriod,
+ "PowerStats",
() -> {
schedulePowerStatsAggregation();
mHandler.post(this::scheduleNextPowerStatsAggregation);
@@ -96,7 +109,7 @@ public class PowerStatsScheduler {
@VisibleForTesting
public void schedulePowerStatsAggregation() {
// Catch up the power stats collectors
- mBatteryStats.schedulePowerStatsSampleCollection();
+ mPowerStatsCollector.run();
mHandler.post(this::aggregateAndStorePowerStats);
}
@@ -105,7 +118,7 @@ public class PowerStatsScheduler {
long currentMonotonicTime = mMonotonicClock.monotonicTime();
long startTime = getLastSavedSpanEndMonotonicTime();
if (startTime < 0) {
- startTime = mBatteryStats.getHistory().getStartTime();
+ startTime = mEarliestAvailableBatteryHistoryTimeMs.get();
}
long endTimeMs = alignToWallClock(startTime + mAggregatedPowerStatsSpanDuration,
mAggregatedPowerStatsSpanDuration, currentMonotonicTime, currentTimeMillis);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index eac4fc00b667..9a85c42e1a10 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1608,14 +1608,12 @@ public class TrustManagerService extends SystemService {
user.name, user.id, user.flags);
if (!user.supportsSwitchToByUser()) {
final boolean locked;
- if (user.isProfile()) {
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id)) {
- fout.print(" (profile with separate challenge)");
- locked = isDeviceLockedInner(user.id);
- } else {
- fout.print(" (profile with unified challenge)");
- locked = isDeviceLockedInner(resolveProfileParent(user.id));
- }
+ if (mLockPatternUtils.isProfileWithUnifiedChallenge(user.id)) {
+ fout.print(" (profile with unified challenge)");
+ locked = isDeviceLockedInner(resolveProfileParent(user.id));
+ } else if (mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id)) {
+ fout.print(" (profile with separate challenge)");
+ locked = isDeviceLockedInner(user.id);
} else {
fout.println(" (user that cannot be switched to)");
locked = isDeviceLockedInner(user.id);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 6f2750767094..d903ad4d9f0d 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -41,7 +41,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
@@ -2081,6 +2080,45 @@ public final class TvInputManagerService extends SystemService {
}
@Override
+ public void stopPlayback(IBinder sessionToken, int mode, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "stopPlayback");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId).stopPlayback(
+ mode);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in stopPlayback(mode)", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void startPlayback(IBinder sessionToken, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "stopPlayback");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId).startPlayback();
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in startPlayback()", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void timeShiftPlay(IBinder sessionToken, final Uri recordedProgramUri, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
diff --git a/services/core/java/com/android/server/vibrator/VibratorControlService.java b/services/core/java/com/android/server/vibrator/VibratorControlService.java
new file mode 100644
index 000000000000..2eeb903bb551
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibratorControlService.java
@@ -0,0 +1,105 @@
+/*
+ * 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.vibrator;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.frameworks.vibrator.IVibratorControlService;
+import android.frameworks.vibrator.IVibratorController;
+import android.frameworks.vibrator.VibrationParam;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Implementation of {@link IVibratorControlService} which allows the registration of
+ * {@link IVibratorController} to set and receive vibration params.
+ *
+ * @hide
+ */
+public final class VibratorControlService extends IVibratorControlService.Stub {
+ private static final String TAG = "VibratorControlService";
+
+ private final VibratorControllerHolder mVibratorControllerHolder;
+ private final Object mLock;
+
+ public VibratorControlService(VibratorControllerHolder vibratorControllerHolder, Object lock) {
+ mVibratorControllerHolder = vibratorControllerHolder;
+ mLock = lock;
+ }
+
+ @Override
+ public void registerVibratorController(IVibratorController controller)
+ throws RemoteException {
+ synchronized (mLock) {
+ mVibratorControllerHolder.setVibratorController(controller);
+ }
+ }
+
+ @Override
+ public void unregisterVibratorController(@NonNull IVibratorController controller)
+ throws RemoteException {
+ Objects.requireNonNull(controller);
+
+ synchronized (mLock) {
+ if (mVibratorControllerHolder.getVibratorController() == null) {
+ Slog.w(TAG, "Received request to unregister IVibratorController = "
+ + controller + ", but no controller was previously registered. Request "
+ + "Ignored.");
+ return;
+ }
+ if (!Objects.equals(mVibratorControllerHolder.getVibratorController().asBinder(),
+ controller.asBinder())) {
+ Slog.wtf(TAG, "Failed to unregister IVibratorController. The provided "
+ + "controller doesn't match the registered one. " + this);
+ return;
+ }
+ mVibratorControllerHolder.setVibratorController(null);
+ }
+ }
+
+ @Override
+ public void setVibrationParams(
+ @SuppressLint("ArrayReturn") VibrationParam[] params, IVibratorController token)
+ throws RemoteException {
+ // TODO(b/305939964): Add set vibration implementation.
+ }
+
+ @Override
+ public void clearVibrationParams(int types, IVibratorController token) throws RemoteException {
+ // TODO(b/305939964): Add clear vibration implementation.
+ }
+
+ @Override
+ public void onRequestVibrationParamsComplete(
+ IBinder requestToken, @SuppressLint("ArrayReturn") VibrationParam[] result)
+ throws RemoteException {
+ // TODO(305942827): Cache the vibration params in VibrationScaler
+ }
+
+ @Override
+ public int getInterfaceVersion() throws RemoteException {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() throws RemoteException {
+ return this.HASH;
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java b/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
new file mode 100644
index 000000000000..63e69db9480f
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
@@ -0,0 +1,70 @@
+/*
+ * 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.vibrator;
+
+import android.annotation.NonNull;
+import android.frameworks.vibrator.IVibratorController;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Holder class for {@link IVibratorController}.
+ *
+ * @hide
+ */
+public final class VibratorControllerHolder implements IBinder.DeathRecipient {
+ private static final String TAG = "VibratorControllerHolder";
+
+ private IVibratorController mVibratorController;
+
+ public IVibratorController getVibratorController() {
+ return mVibratorController;
+ }
+
+ /**
+ * Sets the {@link IVibratorController} in {@link VibratorControllerHolder} to the new
+ * controller. This will also take care of registering and unregistering death notifications
+ * for the cached {@link IVibratorController}.
+ */
+ public void setVibratorController(IVibratorController controller) {
+ try {
+ if (mVibratorController != null) {
+ mVibratorController.asBinder().unlinkToDeath(this, 0);
+ }
+ mVibratorController = controller;
+ if (mVibratorController != null) {
+ mVibratorController.asBinder().linkToDeath(this, 0);
+ }
+ } catch (RemoteException e) {
+ Slog.wtf(TAG, "Failed to set IVibratorController: " + this, e);
+ }
+ }
+
+ @Override
+ public void binderDied(@NonNull IBinder deadBinder) {
+ if (deadBinder == mVibratorController.asBinder()) {
+ setVibratorController(null);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Should not be used as binderDied(IBinder who) is overridden.
+ Slog.wtf(TAG, "binderDied() called unexpectedly.");
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 7d4bd3baf613..fc824abd80f5 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -91,6 +91,8 @@ import java.util.function.Function;
public class VibratorManagerService extends IVibratorManagerService.Stub {
private static final String TAG = "VibratorManagerService";
private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
+ private static final String VIBRATOR_CONTROL_SERVICE =
+ "android.frameworks.vibrator.IVibratorControlService/default";
private static final boolean DEBUG = false;
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
new VibrationAttributes.Builder().build();
@@ -269,6 +271,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
+ if (ServiceManager.isDeclared(VIBRATOR_CONTROL_SERVICE)) {
+ injector.addService(VIBRATOR_CONTROL_SERVICE,
+ new VibratorControlService(new VibratorControllerHolder(), mLock));
+ }
+
}
/** Finish initialization at boot phase {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 315e7d85df24..4b55bec928c7 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -18,17 +18,17 @@ package com.android.server.wm;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.app.Activity.FULLSCREEN_MODE_REQUEST_ENTER;
+import static android.app.Activity.FULLSCREEN_MODE_REQUEST_EXIT;
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.INVALID_WINDOWING_MODE;
import static android.app.FullscreenRequestHandler.REMOTE_CALLBACK_RESULT_KEY;
import static android.app.FullscreenRequestHandler.RESULT_APPROVED;
-import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_DEFAULT_FREEFORM;
-import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_IN_FREEFORM;
import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY;
import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_TOP_FOCUSED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
@@ -1092,19 +1092,14 @@ class ActivityClientController extends IActivityClientController.Stub {
private @FullscreenRequestHandler.RequestResult int validateMultiwindowFullscreenRequestLocked(
Task topFocusedRootTask, int fullscreenRequest, ActivityRecord requesterActivity) {
- // If the mode is not by default freeform, the freeform will be a user-driven event.
- if (topFocusedRootTask.getParent().getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- return RESULT_FAILED_NOT_DEFAULT_FREEFORM;
+ if (requesterActivity.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ return RESULT_APPROVED;
}
// If this is not coming from the currently top-most activity, reject the request.
if (requesterActivity != topFocusedRootTask.getTopMostActivity()) {
return RESULT_FAILED_NOT_TOP_FOCUSED;
}
- if (fullscreenRequest == FULLSCREEN_MODE_REQUEST_ENTER) {
- if (topFocusedRootTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- return RESULT_FAILED_NOT_IN_FREEFORM;
- }
- } else {
+ if (fullscreenRequest == FULLSCREEN_MODE_REQUEST_EXIT) {
if (topFocusedRootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
return RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY;
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
index 81e5fbd564e0..769f01c34e17 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
@@ -142,8 +142,11 @@ public class ActivityMetricsLaunchObserver {
* if the launching activity is started from an existing launch sequence (trampoline)
* but cannot coalesce to the existing one, e.g. to a different display.
* @param name The launching activity name.
+ * @param temperature The temperature at which a launch sequence had started.
+ * @param userId The id of the user the activity is being launched for.
*/
- public void onActivityLaunched(long id, ComponentName name, @Temperature int temperature) {
+ public void onActivityLaunched(long id, ComponentName name, @Temperature int temperature,
+ int userId) {
}
/**
@@ -177,13 +180,15 @@ public class ActivityMetricsLaunchObserver {
* @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds.
* To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted}
* from {@code timestampNanos}.
+ * @param launchMode The activity launch mode.
*
* @apiNote The finishing activity isn't necessarily the same as the starting activity;
* in the case of a trampoline, multiple activities could've been started
* and only the latest activity that was top-most during first-frame drawn
* is reported here.
*/
- public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos) {
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos,
+ int launchMode) {
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 7b20529ce5e1..78f501ad9fed 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -1737,7 +1737,8 @@ class ActivityMetricsLogger {
// Beginning a launch is timing sensitive and so should be observed as soon as possible.
mLaunchObserver.onActivityLaunched(info.mLaunchingState.mStartUptimeNs,
- info.mLastLaunchedActivity.mActivityComponent, temperature);
+ info.mLastLaunchedActivity.mActivityComponent, temperature,
+ info.mLastLaunchedActivity.mUserId);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -1774,7 +1775,8 @@ class ActivityMetricsLogger {
"MetricsLogger:launchObserverNotifyActivityLaunchFinished");
mLaunchObserver.onActivityLaunchFinished(info.mLaunchingState.mStartUptimeNs,
- info.mLastLaunchedActivity.mActivityComponent, timestampNs);
+ info.mLastLaunchedActivity.mActivityComponent, timestampNs,
+ info.mLastLaunchedActivity.launchMode);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index f9d344bd7e31..1b45c1b4f3f1 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -48,6 +48,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -335,19 +336,19 @@ class ActivityStartInterceptor {
return false;
}
final String suspendedPackage = mAInfo.applicationInfo.packageName;
- final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ final UserPackage suspender = pmi.getSuspendingPackage(suspendedPackage, mUserId);
+ if (suspender != null && PLATFORM_PACKAGE_NAME.equals(suspender.packageName)) {
return interceptSuspendedByAdminPackage();
}
final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
- suspendingPackage, mUserId);
+ suspender, mUserId);
final Bundle crossProfileOptions = hasCrossProfileAnimation()
? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
: null;
final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
FLAG_IMMUTABLE);
mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
- suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId);
+ suspender, dialogInfo, crossProfileOptions, target, mUserId);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4b0177a36ebe..630b9e139456 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -84,7 +84,9 @@ import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENS
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -140,6 +142,8 @@ import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.DateFormat;
import java.util.Date;
@@ -230,7 +234,26 @@ class ActivityStarter {
private boolean mIsTaskCleared;
private boolean mMovedToFront;
private boolean mNoAnimation;
- private boolean mAvoidMoveToFront;
+
+ // TODO mAvoidMoveToFront before V is changed from a boolean to a int code mCanMoveToFrontCode
+ // for the purpose of attribution of new BAL V feature. This should be reverted back to the
+ // boolean flag post V.
+ @IntDef(prefix = {"MOVE_TO_FRONT_"}, value = {
+ MOVE_TO_FRONT_ALLOWED,
+ MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS,
+ MOVE_TO_FRONT_AVOID_LEGACY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MoveToFrontCode {}
+
+ // Allows a task move to front.
+ private static final int MOVE_TO_FRONT_ALLOWED = 0;
+ // Avoid a task move to front because the Pending Intent that starts the activity only
+ // its creator has the BAL privilege, its sender does not.
+ private static final int MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS = 1;
+ // Avoid a task move to front because of all other legacy reasons.
+ private static final int MOVE_TO_FRONT_AVOID_LEGACY = 2;
+ private @MoveToFrontCode int mCanMoveToFrontCode = MOVE_TO_FRONT_ALLOWED;
private boolean mFrozeTaskList;
private boolean mTransientLaunch;
// The task which was above the targetTask before starting this activity. null if the targetTask
@@ -642,7 +665,7 @@ class ActivityStarter {
mIsTaskCleared = starter.mIsTaskCleared;
mMovedToFront = starter.mMovedToFront;
mNoAnimation = starter.mNoAnimation;
- mAvoidMoveToFront = starter.mAvoidMoveToFront;
+ mCanMoveToFrontCode = starter.mCanMoveToFrontCode;
mFrozeTaskList = starter.mFrozeTaskList;
mVoiceSession = starter.mVoiceSession;
@@ -1499,6 +1522,14 @@ class ActivityStarter {
return result;
}
+ private boolean avoidMoveToFront() {
+ return mCanMoveToFrontCode != MOVE_TO_FRONT_ALLOWED;
+ }
+
+ private boolean avoidMoveToFrontPIOnlyCreatorAllows() {
+ return mCanMoveToFrontCode == MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS;
+ }
+
/**
* If the start result is success, ensure that the configuration of the started activity matches
* the current display. Otherwise clean up unassociated containers to avoid leakage.
@@ -1552,7 +1583,7 @@ class ActivityStarter {
currentTop, currentTop.getDisplayId(), false /* deferResume */);
}
- if (!mAvoidMoveToFront && mDoResume && mRootWindowContainer
+ if (!avoidMoveToFront() && mDoResume && mRootWindowContainer
.hasVisibleWindowAboveButDoesNotOwnNotificationShade(started.launchedFromUid)) {
// If the UID launching the activity has a visible window on top of the notification
// shade and it's launching an activity that's going to be at the front, we should move
@@ -1689,10 +1720,18 @@ class ActivityStarter {
}
// When running transient transition, the transient launch target should keep on top.
// So disallow the transient hide activity to move itself to front, e.g. trampoline.
- if (!mAvoidMoveToFront && (mService.mHomeProcess == null
+ if (!avoidMoveToFront() && (mService.mHomeProcess == null
|| mService.mHomeProcess.mUid != realCallingUid)
&& r.mTransitionController.isTransientHide(targetTask)) {
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
+ }
+ // If the activity is started by sending a pending intent and only its creator has the
+ // privilege to allow BAL (its sender does not), avoid move it to the front. Only do
+ // this when it is not a new task and not already been marked as avoid move to front.
+ // Guarded by a flag: balDontBringExistingBackgroundTaskStackToFg
+ if (balDontBringExistingBackgroundTaskStackToFg() && !avoidMoveToFront()
+ && balVerdict.onlyCreatorAllows()) {
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS;
}
mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask());
}
@@ -1746,15 +1785,19 @@ class ActivityStarter {
// After activity is attached to task, but before actual start
recordTransientLaunchIfNeeded(mLastStartActivityRecord);
- if (!mAvoidMoveToFront && mDoResume) {
- logOnlyCreatorAllowsBAL(balVerdict, realCallingUid, newTask);
- mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
- if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
- && !dreamStopping) {
- // Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
- // -behind transition so the Activity gets created and starts in visible state.
- mLaunchTaskBehind = true;
- r.mLaunchTaskBehind = true;
+ if (mDoResume) {
+ if (!avoidMoveToFront()) {
+ mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
+ if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
+ && !dreamStopping) {
+ // Launching underneath dream activity (fullscreen, always-on-top). Run the
+ // launch--behind transition so the Activity gets created and starts
+ // in visible state.
+ mLaunchTaskBehind = true;
+ r.mLaunchTaskBehind = true;
+ }
+ } else {
+ logPIOnlyCreatorAllowsBAL();
}
}
@@ -1816,10 +1859,13 @@ class ActivityStarter {
// root-task to the will not update the focused root-task. If starting the new
// activity now allows the task root-task to be focusable, then ensure that we
// now update the focused root-task accordingly.
- if (!mAvoidMoveToFront && mTargetRootTask.isTopActivityFocusable()
+ if (mTargetRootTask.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
- logOnlyCreatorAllowsBAL(balVerdict, realCallingUid, newTask);
- mTargetRootTask.moveToFront("startActivityInner");
+ if (!avoidMoveToFront()) {
+ mTargetRootTask.moveToFront("startActivityInner");
+ } else {
+ logPIOnlyCreatorAllowsBAL();
+ }
}
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
@@ -1847,25 +1893,24 @@ class ActivityStarter {
return START_SUCCESS;
}
- private void logOnlyCreatorAllowsBAL(BalVerdict balVerdict,
- int realCallingUid, boolean newTask) {
- // TODO (b/296478675) eventually, we will prevent such case from happening
- // and probably also log that a BAL is prevented by android V.
- if (!newTask && balVerdict.onlyCreatorAllows()) {
- String realCallingPackage =
- mService.mContext.getPackageManager().getNameForUid(realCallingUid);
- if (realCallingPackage == null) {
- realCallingPackage = "uid=" + realCallingUid;
- }
- Slog.wtf(TAG, "A background app is brought to the foreground due to a "
- + "PendingIntent. However, only the creator of the PendingIntent allows BAL, "
- + "while the sender does not allow BAL. realCallingPackage: "
- + realCallingPackage + "; callingPackage: " + mRequest.callingPackage
- + "; mTargetRootTask:" + mTargetRootTask + "; mIntent: " + mIntent
- + "; mTargetRootTask.getTopNonFinishingActivity: "
- + mTargetRootTask.getTopNonFinishingActivity()
- + "; mTargetRootTask.getRootActivity: " + mTargetRootTask.getRootActivity());
+ // TODO (b/316135632) Post V release, remove this log method.
+ private void logPIOnlyCreatorAllowsBAL() {
+ if (!avoidMoveToFrontPIOnlyCreatorAllows()) return;
+ String realCallingPackage =
+ mService.mContext.getPackageManager().getNameForUid(mRealCallingUid);
+ if (realCallingPackage == null) {
+ realCallingPackage = "uid=" + mRealCallingUid;
}
+ Slog.wtf(TAG, "Without Android 15 BAL hardening this activity would be moved to the "
+ + "foreground. The activity is started by a PendingIntent. However, only the "
+ + "creator of the PendingIntent allows BAL while the sender does not allow BAL. "
+ + "realCallingPackage: " + realCallingPackage
+ + "; callingPackage: " + mRequest.callingPackage
+ + "; mTargetRootTask:" + mTargetRootTask
+ + "; mIntent: " + mIntent
+ + "; mTargetRootTask.getTopNonFinishingActivity: "
+ + mTargetRootTask.getTopNonFinishingActivity()
+ + "; mTargetRootTask.getRootActivity: " + mTargetRootTask.getRootActivity());
}
private void recordTransientLaunchIfNeeded(ActivityRecord r) {
@@ -2064,7 +2109,7 @@ class ActivityStarter {
mRootWindowContainer.startPowerModeLaunchIfNeeded(false /* forceSend */,
targetTaskTop);
- setTargetRootTaskIfNeeded(targetTaskTop, balVerdict);
+ setTargetRootTaskIfNeeded(targetTaskTop);
// When there is a reused activity and the current result is a trampoline activity,
// set the reused activity as the result.
@@ -2080,13 +2125,12 @@ class ActivityStarter {
if (!mMovedToFront && mDoResume) {
ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetRootTask,
targetTaskTop);
- logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
mTargetRootTask.moveToFront("intentActivityFound");
}
+
resumeTargetRootTaskIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
-
complyActivityFlags(targetTask,
reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null, intentGrants);
@@ -2109,7 +2153,6 @@ class ActivityStarter {
targetTaskTop.showStartingWindow(true /* taskSwitch */);
} else if (mDoResume) {
// Make sure the root task and its belonging display are moved to topmost.
- logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
mTargetRootTask.moveToFront("intentActivityFound");
}
// We didn't do anything... but it was needed (a.k.a., client don't use that intent!)
@@ -2344,7 +2387,7 @@ class ActivityStarter {
mIsTaskCleared = false;
mMovedToFront = false;
mNoAnimation = false;
- mAvoidMoveToFront = false;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_ALLOWED;
mFrozeTaskList = false;
mTransientLaunch = false;
mPriorAboveTask = null;
@@ -2456,12 +2499,12 @@ class ActivityStarter {
// The caller specifies that we'd like to be avoided to be moved to the
// front, so be it!
mDoResume = false;
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
}
} else if (mOptions.getAvoidMoveToFront()) {
mDoResume = false;
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
mTransientLaunch = mOptions.getTransientLaunch();
final KeyguardController kc = mSupervisor.getKeyguardController();
@@ -2471,7 +2514,7 @@ class ActivityStarter {
if (mTransientLaunch && mDisplayLockAndOccluded
&& mService.getTransitionController().isShellTransitionsEnabled()) {
mDoResume = false;
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
@@ -2528,7 +2571,7 @@ class ActivityStarter {
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
if (mBalCode == BAL_BLOCK && !mService.isBackgroundActivityStartsEnabled()) {
- mAvoidMoveToFront = true;
+ mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
mDoResume = false;
}
}
@@ -2705,7 +2748,7 @@ class ActivityStarter {
* @param intentActivity Existing matching activity.
* @return {@link ActivityRecord} brought to front.
*/
- private void setTargetRootTaskIfNeeded(ActivityRecord intentActivity, BalVerdict balVerdict) {
+ private void setTargetRootTaskIfNeeded(ActivityRecord intentActivity) {
intentActivity.getTaskFragment().clearLastPausedActivity();
Task intentTask = intentActivity.getTask();
// The intent task might be reparented while in getOrCreateRootTask, caches the original
@@ -2742,7 +2785,7 @@ class ActivityStarter {
differentTopTask = true;
}
- if (differentTopTask && !mAvoidMoveToFront) {
+ if (differentTopTask && !avoidMoveToFront()) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (mSourceRecord == null || inTopNonFinishingTask(mSourceRecord)) {
// We really do want to push this one into the user's face, right now.
@@ -2772,7 +2815,6 @@ class ActivityStarter {
// task on top there.
// Defer resuming the top activity while moving task to top, since the
// current task-top activity may not be the activity that should be resumed.
- logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
mTargetRootTask.moveTaskToFront(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, DEFER_RESUME,
"bringingFoundTaskToFront");
@@ -2789,7 +2831,9 @@ class ActivityStarter {
mOptions = null;
}
}
-
+ if (differentTopTask) {
+ logPIOnlyCreatorAllowsBAL();
+ }
// Update the target's launch cookie and pending remote animation to those specified in the
// options if set.
if (mStartActivity.mLaunchCookie != null) {
@@ -2840,7 +2884,7 @@ class ActivityStarter {
}
private void setNewTask(Task taskToAffiliate) {
- final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
+ final boolean toTop = !mLaunchTaskBehind && !avoidMoveToFront();
final Task task = mTargetRootTask.reuseOrCreateTask(
mStartActivity.info, mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 73edb4bed6ca..869bcc0f9b8f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1053,6 +1053,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mWindowManager = wm;
mRootWindowContainer = wm.mRoot;
mWindowOrganizerController.mTransitionController.setWindowManager(wm);
+ mLifecycleManager.setWindowManager(wm);
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
@@ -1274,7 +1275,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
-
final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
assertPackageMatchesCallingUid(callingPackage);
@@ -1315,7 +1315,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
.setActivityOptions(opts)
.setUserId(userId)
.execute();
-
}
@Override
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 92665af1075b..4929df8061b2 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static android.os.Process.SYSTEM_UID;
import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
@@ -49,7 +50,6 @@ import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.provider.DeviceConfig;
@@ -86,7 +86,7 @@ public class BackgroundActivityStartController {
private static final int NO_PROCESS_UID = -1;
/** If enabled the creator will not allow BAL on its behalf by default. */
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @EnabledAfter(targetSdkVersion = UPSIDE_DOWN_CAKE)
private static final long DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_CREATOR =
296478951;
public static final ActivityOptions ACTIVITY_OPTIONS_SYSTEM_DEFINED =
@@ -228,6 +228,7 @@ public class BackgroundActivityStartController {
private final Intent mIntent;
private final WindowProcessController mCallerApp;
private final WindowProcessController mRealCallerApp;
+ private final boolean mIsCallForResult;
private BalState(int callingUid, int callingPid, final String callingPackage,
int realCallingUid, int realCallingPid,
@@ -247,8 +248,10 @@ public class BackgroundActivityStartController {
mOriginatingPendingIntent = originatingPendingIntent;
mIntent = intent;
mRealCallingPackage = mService.getPackageNameIfUnique(realCallingUid, realCallingPid);
- if (originatingPendingIntent == null // not a PendingIntent
- || resultRecord != null // sent for result
+ mIsCallForResult = resultRecord != null;
+ if (balRequireOptInByPendingIntentCreator() // auto-opt in introduced with this feature
+ && (originatingPendingIntent == null // not a PendingIntent
+ || mIsCallForResult) // sent for result
) {
// grant BAL privileges unless explicitly opted out
mBalAllowedByPiCreatorWithHardening = mBalAllowedByPiCreator =
@@ -351,6 +354,19 @@ public class BackgroundActivityStartController {
return name + "[debugOnly]";
}
+ /** @return valid targetSdk or <code>-1</code> */
+ private int getTargetSdk(String packageName) {
+ if (packageName == null) {
+ return -1;
+ }
+ try {
+ PackageManager pm = mService.mContext.getPackageManager();
+ return pm.getTargetSdkVersion(packageName);
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
private boolean hasRealCaller() {
return mRealCallingUid != NO_PROCESS_UID;
}
@@ -368,6 +384,7 @@ public class BackgroundActivityStartController {
StringBuilder sb = new StringBuilder(2048);
sb.append("[callingPackage: ")
.append(getDebugPackageName(mCallingPackage, mCallingUid));
+ sb.append("; callingPackageTargetSdk: ").append(getTargetSdk(mCallingPackage));
sb.append("; callingUid: ").append(mCallingUid);
sb.append("; callingPid: ").append(mCallingPid);
sb.append("; appSwitchState: ").append(mAppSwitchState);
@@ -387,10 +404,13 @@ public class BackgroundActivityStartController {
.append(mBalAllowedByPiCreatorWithHardening);
sb.append("; resultIfPiCreatorAllowsBal: ").append(resultIfPiCreatorAllowsBal);
sb.append("; hasRealCaller: ").append(hasRealCaller());
+ sb.append("; isCallForResult: ").append(mIsCallForResult);
sb.append("; isPendingIntent: ").append(isPendingIntent());
if (hasRealCaller()) {
sb.append("; realCallingPackage: ")
.append(getDebugPackageName(mRealCallingPackage, mRealCallingUid));
+ sb.append("; realCallingPackageTargetSdk: ")
+ .append(getTargetSdk(mRealCallingPackage));
sb.append("; realCallingUid: ").append(mRealCallingUid);
sb.append("; realCallingPid: ").append(mRealCallingPid);
sb.append("; realCallingUidHasAnyVisibleWindow: ")
diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
index 8b282dd3e7a8..6b6388b10ce7 100644
--- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
@@ -22,7 +22,13 @@ import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
/**
* Class that is able to combine multiple client lifecycle transition requests and/or callbacks,
@@ -31,8 +37,18 @@ import android.os.RemoteException;
* @see ClientTransaction
*/
class ClientLifecycleManager {
- // TODO(lifecycler): Implement building transactions or global transaction.
- // TODO(lifecycler): Use object pools for transactions and transaction items.
+
+ private static final String TAG = "ClientLifecycleManager";
+
+ /** Mapping from client process binder to its pending transaction. */
+ @VisibleForTesting
+ final ArrayMap<IBinder, ClientTransaction> mPendingTransactions = new ArrayMap<>();
+
+ private WindowManagerService mWms;
+
+ void setWindowManager(@NonNull WindowManagerService wms) {
+ mWms = wms;
+ }
/**
* Schedules a transaction, which may consist of multiple callbacks and a lifecycle request.
@@ -82,14 +98,24 @@ class ClientLifecycleManager {
*/
void scheduleTransactionItem(@NonNull IApplicationThread client,
@NonNull ClientTransactionItem transactionItem) throws RemoteException {
- // TODO(b/260873529): queue the transaction items.
- final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
- if (transactionItem.isActivityLifecycleItem()) {
- clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
+ // The behavior is different depending on the flag.
+ // When flag is on, we wait until RootWindowContainer#performSurfacePlacementNoTrace to
+ // dispatch all pending transactions at once.
+ if (Flags.bundleClientTransactionFlag()) {
+ final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client);
+ clientTransaction.addTransactionItem(transactionItem);
+
+ onClientTransactionItemScheduledLocked(clientTransaction);
} else {
- clientTransaction.addCallback(transactionItem);
+ // TODO(b/260873529): cleanup after launch.
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
+ if (transactionItem.isActivityLifecycleItem()) {
+ clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
+ } else {
+ clientTransaction.addCallback(transactionItem);
+ }
+ scheduleTransaction(clientTransaction);
}
- scheduleTransaction(clientTransaction);
}
/**
@@ -100,10 +126,67 @@ class ClientLifecycleManager {
void scheduleTransactionAndLifecycleItems(@NonNull IApplicationThread client,
@NonNull ClientTransactionItem transactionItem,
@NonNull ActivityLifecycleItem lifecycleItem) throws RemoteException {
- // TODO(b/260873529): replace with #scheduleTransactionItem after launch for cleanup.
- final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
- clientTransaction.addCallback(transactionItem);
- clientTransaction.setLifecycleStateRequest(lifecycleItem);
+ // The behavior is different depending on the flag.
+ // When flag is on, we wait until RootWindowContainer#performSurfacePlacementNoTrace to
+ // dispatch all pending transactions at once.
+ if (Flags.bundleClientTransactionFlag()) {
+ final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client);
+ clientTransaction.addTransactionItem(transactionItem);
+ clientTransaction.addTransactionItem(lifecycleItem);
+
+ onClientTransactionItemScheduledLocked(clientTransaction);
+ } else {
+ // TODO(b/260873529): cleanup after launch.
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
+ clientTransaction.addCallback(transactionItem);
+ clientTransaction.setLifecycleStateRequest(lifecycleItem);
+ scheduleTransaction(clientTransaction);
+ }
+ }
+
+ /** Executes all the pending transactions. */
+ void dispatchPendingTransactions() {
+ final int size = mPendingTransactions.size();
+ for (int i = 0; i < size; i++) {
+ final ClientTransaction transaction = mPendingTransactions.valueAt(i);
+ try {
+ scheduleTransaction(transaction);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to deliver transaction for " + transaction.getClient());
+ }
+ }
+ mPendingTransactions.clear();
+ }
+
+ @NonNull
+ private ClientTransaction getOrCreatePendingTransaction(@NonNull IApplicationThread client) {
+ final IBinder clientBinder = client.asBinder();
+ final ClientTransaction pendingTransaction = mPendingTransactions.get(clientBinder);
+ if (pendingTransaction != null) {
+ return pendingTransaction;
+ }
+
+ // Create new transaction if there is no existing.
+ final ClientTransaction transaction = ClientTransaction.obtain(client);
+ mPendingTransactions.put(clientBinder, transaction);
+ return transaction;
+ }
+
+ /** Must only be called with WM lock. */
+ private void onClientTransactionItemScheduledLocked(
+ @NonNull ClientTransaction clientTransaction) throws RemoteException {
+ // TODO(b/260873529): make sure WindowSurfacePlacer#requestTraversal is called before
+ // ClientTransaction scheduled when needed.
+
+ if (mWms != null && (mWms.mWindowPlacerLocked.isInLayout()
+ || mWms.mWindowPlacerLocked.isTraversalScheduled())) {
+ // The pending transactions will be dispatched when
+ // RootWindowContainer#performSurfacePlacementNoTrace.
+ return;
+ }
+
+ // Dispatch the pending transaction immediately.
+ mPendingTransactions.remove(clientTransaction.getClient().asBinder());
scheduleTransaction(clientTransaction);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 03d6c2cab828..ae10ce3690aa 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5149,8 +5149,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** @return the orientation of the display when it's rotation is ROTATION_0. */
int getNaturalOrientation() {
- return mBaseDisplayWidth < mBaseDisplayHeight
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ final Configuration config = getConfiguration();
+ if (config.windowConfiguration.getDisplayRotation() == ROTATION_0) {
+ return config.orientation;
+ }
+ final Rect frame = mDisplayPolicy.getDecorInsetsInfo(
+ ROTATION_0, mBaseDisplayWidth, mBaseDisplayHeight).mConfigFrame;
+ return frame.width() <= frame.height() ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
}
void performLayout(boolean initial, boolean updateInputWindows) {
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 4a3d0c142e1d..32d60c5f52e6 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.input.flags.Flags.enablePointerChoreographer;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -23,6 +24,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.content.ClipData;
import android.content.Context;
+import android.hardware.input.InputManagerGlobal;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -31,6 +33,8 @@ import android.os.Message;
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
+import android.view.InputDevice;
+import android.view.PointerIcon;
import android.view.SurfaceControl;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
@@ -97,8 +101,8 @@ class DragDropController {
}
IBinder performDrag(int callerPid, int callerUid, IWindow window, int flags,
- SurfaceControl surface, int touchSource, float touchX, float touchY,
- float thumbCenterX, float thumbCenterY, ClipData data) {
+ SurfaceControl surface, int touchSource, int touchDeviceId, int touchPointerId,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" +
Integer.toHexString(flags) + " data=" + data + " touch(" + touchX + ","
@@ -208,7 +212,17 @@ class DragDropController {
final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
mDragState.broadcastDragStartedLocked(touchX, touchY);
- mDragState.overridePointerIconLocked(touchSource);
+ if (enablePointerChoreographer()) {
+ if ((touchSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
+ InputManagerGlobal.getInstance().setPointerIcon(
+ PointerIcon.getSystemIcon(
+ mService.mContext, PointerIcon.TYPE_GRABBING),
+ mDragState.mDisplayContent.getDisplayId(), touchDeviceId,
+ touchPointerId, mDragState.getInputToken());
+ }
+ } else {
+ mDragState.overridePointerIconLocked(touchSource);
+ }
// remember the thumb offsets for later
mDragState.mThumbOffsetX = thumbCenterX;
mDragState.mThumbOffsetY = thumbCenterY;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index a888f8467b3a..adbe3bc1d6b3 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -416,6 +416,13 @@ class DragState {
return mInputInterceptor == null ? null : mInputInterceptor.mDragWindowHandle;
}
+ IBinder getInputToken() {
+ if (mInputInterceptor == null || mInputInterceptor.mClientChannel == null) {
+ return null;
+ }
+ return mInputInterceptor.mClientChannel.getToken();
+ }
+
/**
* @param display The Display that the window being dragged is on.
*/
diff --git a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
index 9cbc1bdcbeeb..4c73a415d3f3 100644
--- a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
+++ b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
@@ -84,10 +84,10 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
@Override
- public void onActivityLaunched(long id, ComponentName name, int temperature) {
+ public void onActivityLaunched(long id, ComponentName name, int temperature, int userId) {
mHandler.sendMessage(PooledLambda.obtainMessage(
LaunchObserverRegistryImpl::handleOnActivityLaunched,
- this, id, name, temperature));
+ this, id, name, temperature, userId));
}
@Override
@@ -97,10 +97,11 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
@Override
- public void onActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNs,
+ int launchMode) {
mHandler.sendMessage(PooledLambda.obtainMessage(
LaunchObserverRegistryImpl::handleOnActivityLaunchFinished,
- this, id, name, timestampNs));
+ this, id, name, timestampNs, launchMode));
}
@Override
@@ -137,10 +138,10 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
private void handleOnActivityLaunched(long id, ComponentName name,
- @Temperature int temperature) {
+ @Temperature int temperature, int userId) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- mList.get(i).onActivityLaunched(id, name, temperature);
+ mList.get(i).onActivityLaunched(id, name, temperature, userId);
}
}
@@ -151,10 +152,11 @@ class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implement
}
}
- private void handleOnActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
+ private void handleOnActivityLaunchFinished(long id, ComponentName name, long timestampNs,
+ int launchMode) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- mList.get(i).onActivityLaunchFinished(id, name, timestampNs);
+ mList.get(i).onActivityLaunchFinished(id, name, timestampNs, launchMode);
}
}
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 0d15fc932e68..2b841fdad9c0 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
@@ -110,15 +111,6 @@ public class PhysicalDisplaySwitchTransitionLauncher {
return;
}
- final TransitionRequestInfo.DisplayChange displayChange =
- new TransitionRequestInfo.DisplayChange(displayId);
-
- final Rect startAbsBounds = new Rect(0, 0, oldDisplayWidth, oldDisplayHeight);
- displayChange.setStartAbsBounds(startAbsBounds);
- final Rect endAbsBounds = new Rect(0, 0, newDisplayWidth, newDisplayHeight);
- displayChange.setEndAbsBounds(endAbsBounds);
- displayChange.setPhysicalDisplayChanged(true);
-
mTransition = null;
if (mTransitionController.isCollecting()) {
@@ -128,10 +120,20 @@ public class PhysicalDisplaySwitchTransitionLauncher {
// Make sure that transition is not ready until we finish the remote display change
mTransition.setReady(mDisplayContent, false);
+ mTransition.addFlag(TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH);
ProtoLog.d(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Adding display switch to existing collecting transition");
} else {
+ final TransitionRequestInfo.DisplayChange displayChange =
+ new TransitionRequestInfo.DisplayChange(displayId);
+
+ final Rect startAbsBounds = new Rect(0, 0, oldDisplayWidth, oldDisplayHeight);
+ displayChange.setStartAbsBounds(startAbsBounds);
+ final Rect endAbsBounds = new Rect(0, 0, newDisplayWidth, newDisplayHeight);
+ displayChange.setEndAbsBounds(endAbsBounds);
+ displayChange.setPhysicalDisplayChanged(true);
+
mTransition = mTransitionController.requestTransitionIfNeeded(TRANSIT_CHANGE,
0 /* flags */,
mDisplayContent, mDisplayContent, null /* remoteTransition */,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d5aa2760d41a..9a75dae3569e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -842,6 +842,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
handleResizingWindows();
clearFrameChangingWindows();
+ // Called after #handleResizingWindows to include WindowStateResizeItem if any.
+ mWmService.mAtmService.getLifecycleManager().dispatchPendingTransactions();
+
if (mWmService.mDisplayFrozen) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"With display frozen, orientationChangeComplete=%b",
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 56f9aa4c6361..57939bc4f348 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -340,7 +340,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
- float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
+ int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
+ float thumbCenterY, ClipData data) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
// Validate and resolve ClipDescription data before clearing the calling identity
@@ -349,7 +350,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
- touchX, touchY, thumbCenterX, thumbCenterY, data);
+ touchDeviceId, touchPointerId, touchX, touchY, thumbCenterX, thumbCenterY,
+ data);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index fc92755c6550..5d019122d52e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -73,6 +73,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
+import android.app.IApplicationThread;
import android.app.ResultInfo;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityResultItem;
@@ -103,6 +104,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.am.HostingRecord;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.window.flags.Flags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1509,23 +1511,38 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
try {
- final ClientTransaction transaction = ClientTransaction.obtain(
- next.app.getThread());
+ final IApplicationThread appThread = next.app.getThread();
+ final ClientTransaction transaction = Flags.bundleClientTransactionFlag()
+ ? null
+ : ClientTransaction.obtain(appThread);
// Deliver all pending results.
- ArrayList<ResultInfo> a = next.results;
+ final ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int size = a.size();
if (!next.finishing && size > 0) {
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
}
- transaction.addCallback(ActivityResultItem.obtain(next.token, a));
+ final ActivityResultItem activityResultItem = ActivityResultItem.obtain(
+ next.token, a);
+ if (transaction == null) {
+ mAtmService.getLifecycleManager().scheduleTransactionItem(
+ appThread, activityResultItem);
+ } else {
+ transaction.addCallback(activityResultItem);
+ }
}
}
if (next.newIntents != null) {
- transaction.addCallback(
- NewIntentItem.obtain(next.token, next.newIntents, true /* resume */));
+ final NewIntentItem newIntentItem = NewIntentItem.obtain(
+ next.token, next.newIntents, true /* resume */);
+ if (transaction == null) {
+ mAtmService.getLifecycleManager().scheduleTransactionItem(
+ appThread, newIntentItem);
+ } else {
+ transaction.addCallback(newIntentItem);
+ }
}
// Well the app will no longer be stopped.
@@ -1539,10 +1556,16 @@ class TaskFragment extends WindowContainer<WindowContainer> {
final int topProcessState = mAtmService.mTopProcessState;
next.app.setPendingUiCleanAndForceProcessStateUpTo(topProcessState);
next.abortAndClearOptionsAnimation();
- transaction.setLifecycleStateRequest(
- ResumeActivityItem.obtain(next.token, topProcessState,
- dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus()));
- mAtmService.getLifecycleManager().scheduleTransaction(transaction);
+ final ResumeActivityItem resumeActivityItem = ResumeActivityItem.obtain(
+ next.token, topProcessState, dc.isNextTransitionForward(),
+ next.shouldSendCompatFakeFocus());
+ if (transaction == null) {
+ mAtmService.getLifecycleManager().scheduleTransactionItem(
+ appThread, resumeActivityItem);
+ } else {
+ transaction.setLifecycleStateRequest(resumeActivityItem);
+ mAtmService.getLifecycleManager().scheduleTransaction(transaction);
+ }
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 808a11d4adae..516d37c0136a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -866,6 +866,11 @@ public abstract class WindowManagerInternal {
public abstract ImeTargetInfo onToggleImeRequested(boolean show,
@NonNull IBinder focusedToken, @NonNull IBinder requestToken, int displayId);
+ /**
+ * Returns the token to identify the target window that the IME is associated with.
+ */
+ public abstract @Nullable IBinder getTargetWindowTokenFromInputToken(IBinder inputToken);
+
/** The information of input method target when IME is requested to show or hide. */
public static class ImeTargetInfo {
public final String focusedWindowName;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 10dd334ed50c..2125c63eed34 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8552,6 +8552,12 @@ public class WindowManagerService extends IWindowManager.Stub
fromOrientations, toOrientations);
}
}
+
+ @Override
+ public @Nullable IBinder getTargetWindowTokenFromInputToken(IBinder inputToken) {
+ InputTarget inputTarget = WindowManagerService.this.getInputTargetFromToken(inputToken);
+ return inputTarget == null ? null : inputTarget.getWindowToken();
+ }
}
private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index a872fd0baaae..4b99432b2943 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -63,6 +63,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
@@ -1178,6 +1179,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mService.mRootWindowContainer.moveActivityToPinnedRootTask(
pipActivity, null /* launchIntoPipHostActivity */,
"moveActivityToPinnedRootTask", null /* transition */, entryBounds);
+
+ // Continue the pausing process after potential task reparenting.
+ if (pipActivity.isState(PAUSING) && pipActivity.mPauseSchedulePendingForPip) {
+ pipActivity.getTask().schedulePauseActivity(
+ pipActivity, false /* userLeaving */,
+ false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip");
+ }
+
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index fd5f7a3f5cfa..5721750fbf63 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -66,6 +66,7 @@ import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Build;
+import android.os.DeadObjectException;
import android.os.FactoryTest;
import android.os.LocaleList;
import android.os.Message;
@@ -1675,6 +1676,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@NonNull ClientTransactionItem transactionItem) {
try {
mAtm.getLifecycleManager().scheduleTransactionItem(thread, transactionItem);
+ } catch (DeadObjectException e) {
+ // Expected if the process has been killed.
+ Slog.w(TAG_CONFIGURATION, "Failed for dead process. ClientTransactionItem="
+ + transactionItem + " owner=" + mOwner);
} catch (Exception e) {
Slog.e(TAG_CONFIGURATION, "Failed to schedule ClientTransactionItem="
+ transactionItem + " owner=" + mOwner, e);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index aa589024fdc6..dff718a4b7d5 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -210,6 +210,10 @@ class WindowSurfacePlacer {
return mInLayout;
}
+ boolean isTraversalScheduled() {
+ return mTraversalScheduled;
+ }
+
void requestTraversal() {
if (mTraversalScheduled) {
return;
diff --git a/services/core/jni/com_android_server_app_GameManagerService.cpp b/services/core/jni/com_android_server_app_GameManagerService.cpp
index 3028813d0d5a..f593f4077365 100644
--- a/services/core/jni/com_android_server_app_GameManagerService.cpp
+++ b/services/core/jni/com_android_server_app_GameManagerService.cpp
@@ -25,15 +25,21 @@
namespace android {
-static void android_server_app_GameManagerService_nativeSetOverrideFrameRate(JNIEnv* env,
- jclass clazz, jint uid,
- jfloat frameRate) {
- SurfaceComposerClient::setOverrideFrameRate(uid, frameRate);
+static void android_server_app_GameManagerService_nativeSetGameModeFrameRateOverride(
+ JNIEnv* env, jclass clazz, jint uid, jfloat frameRate) {
+ SurfaceComposerClient::setGameModeFrameRateOverride(uid, frameRate);
+}
+
+static void android_server_app_GameManagerService_nativeSetGameDefaultFrameRateOverride(
+ JNIEnv* env, jclass clazz, jint uid, jfloat frameRate) {
+ SurfaceComposerClient::setGameDefaultFrameRateOverride(uid, frameRate);
}
static const JNINativeMethod gMethods[] = {
- {"nativeSetOverrideFrameRate", "(IF)V",
- (void*)android_server_app_GameManagerService_nativeSetOverrideFrameRate},
+ {"nativeSetGameModeFrameRateOverride", "(IF)V",
+ (void*)android_server_app_GameManagerService_nativeSetGameModeFrameRateOverride},
+ {"nativeSetGameDefaultFrameRateOverride", "(IF)V",
+ (void*)android_server_app_GameManagerService_nativeSetGameDefaultFrameRateOverride},
};
int register_android_server_app_GameManagerService(JNIEnv* env) {
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 3d4f866948af..2a0f1e2ede55 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -182,7 +182,7 @@ static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
auto hash_block_count = block_count;
- for (auto i = 0; hash_block_count > 1; i++) {
+ while (hash_block_count > 1) {
hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
total_tree_block_count += hash_block_count;
}
@@ -468,7 +468,6 @@ private:
borrowed_fd incomingFd, bool waitOnEof, std::vector<char>* buffer,
std::vector<IncFsDataBlock>* blocks) {
IncFsSize remaining = size;
- IncFsSize totalSize = 0;
IncFsBlockIndex blockIdx = 0;
while (remaining > 0) {
constexpr auto capacity = BUFFER_SIZE;
@@ -502,7 +501,6 @@ private:
buffer->resize(size + read);
remaining -= read;
- totalSize += read;
}
if (!buffer->empty() && !flashToIncFs(incfsFd, kind, true, &blockIdx, buffer, blocks)) {
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e0a2f30b1831..a490013303e9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2469,7 +2469,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void migratePersonalAppSuspensionLocked(
int doUserId, int poUserId, ActiveAdmin poAdmin) {
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
- if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
+ if (!pmi.isAdminSuspendingAnyPackages(doUserId)) {
Slogf.i(LOG_TAG, "DO is not suspending any apps.");
return;
}
@@ -2480,7 +2480,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
poAdmin.mSuspendPersonalApps = true;
} else {
Slogf.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
- pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
+ pmi.unsuspendAdminSuspendedPackages(doUserId);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 6570ce1cd500..506dbe8c48c4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -16,8 +16,6 @@
package com.android.server.devicepolicy;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
@@ -287,7 +285,7 @@ final class PolicyEnforcerCallbacks {
suspendPersonalAppsInPackageManager(context, userId);
} else {
LocalServices.getService(PackageManagerInternal.class)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, userId);
+ .unsuspendAdminSuspendedPackages(userId);
}
});
return true;
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
index 47c2a1b079f8..29e258cc90ff 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
@@ -5,4 +5,12 @@ flag {
namespace: "display_manager"
description: "Feature flag for dual display blocking"
bug: "278667199"
+}
+
+flag {
+ name: "enable_foldables_posture_based_closed_state"
+ namespace: "windowing_frontend"
+ description: "Enables smarter closed device state state for foldable devices"
+ bug: "309792734"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/services/manifest_services.xml b/services/manifest_services.xml
index 76389154a885..eae159fe9e89 100644
--- a/services/manifest_services.xml
+++ b/services/manifest_services.xml
@@ -4,4 +4,9 @@
<version>1</version>
<fqname>IAltitudeService/default</fqname>
</hal>
+ <hal format="aidl">
+ <name>android.frameworks.vibrator</name>
+ <version>1</version>
+ <fqname>IVibratorControlService/default</fqname>
+ </hal>
</manifest>
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 02032c786563..f69f6283f968 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -24,6 +24,7 @@ import android.content.pm.SigningDetails
import android.os.Build
import android.util.Slog
import com.android.internal.os.RoSystemProperties
+import com.android.internal.pm.permission.CompatibilityPermissionInfo
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
@@ -42,7 +43,6 @@ import com.android.server.permission.access.util.hasBits
import com.android.server.permission.access.util.isInternal
import com.android.server.pm.KnownPackages
import com.android.server.pm.parsing.PackageInfoUtils
-import com.android.server.pm.permission.CompatibilityPermissionInfo
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
index ea5fb5d62fad..a0fb0138e5e5 100644
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
@@ -16,9 +16,7 @@
package com.android.server.permission.access.permission
-import android.Manifest
import android.permission.PermissionManager
-import android.permission.flags.Flags
import android.util.Slog
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
@@ -61,7 +59,7 @@ class DevicePermissionPolicy : SchemePolicy() {
}
}
- fun MutateStateScope.removeInactiveDevicesPermission(activePersistentDeviceIds: Set<String>) {
+ fun MutateStateScope.trimDevicePermissionStates(deviceIds: Set<String>) {
newState.userStates.forEachIndexed { _, userId, userState ->
userState.appIdDevicePermissionFlags.forEachReversedIndexed { _, appId, _ ->
val appIdDevicePermissionFlags =
@@ -69,14 +67,11 @@ class DevicePermissionPolicy : SchemePolicy() {
val devicePermissionFlags =
appIdDevicePermissionFlags.mutate(appId) ?: return@forEachReversedIndexed
- val removePersistentDeviceIds = mutableSetOf<String>()
- devicePermissionFlags.forEachIndexed { _, deviceId, _ ->
- if (!activePersistentDeviceIds.contains(deviceId)) {
- removePersistentDeviceIds.add(deviceId)
+ devicePermissionFlags.forEachReversedIndexed { _, deviceId, _ ->
+ if (deviceId !in deviceIds) {
+ devicePermissionFlags -= deviceId
}
}
-
- removePersistentDeviceIds.forEach { deviceId -> devicePermissionFlags -= deviceId }
}
}
}
@@ -122,6 +117,10 @@ class DevicePermissionPolicy : SchemePolicy() {
resetRuntimePermissions(packageName, userId)
}
+ /**
+ * Reset permission states for all permissions requested by the given package, if no other
+ * package (sharing the App ID) request these permissions.
+ */
fun MutateStateScope.resetRuntimePermissions(packageName: String, userId: Int) {
// It's okay to skip resetting permissions for packages that are removed,
// because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
@@ -144,6 +143,7 @@ class DevicePermissionPolicy : SchemePolicy() {
}
}
+ // Trims permission state for permissions not requested by the App ID anymore.
private fun MutateStateScope.trimPermissionStates(appId: Int) {
val requestedPermissions = MutableIndexedSet<String>()
forEachPackageInAppId(appId) {
@@ -245,10 +245,6 @@ class DevicePermissionPolicy : SchemePolicy() {
flagMask: Int,
flagValues: Int
): Boolean {
- if (!isDeviceAwarePermission(permissionName)) {
- Slog.w(LOG_TAG, "$permissionName is not a device aware permission.")
- return false
- }
val oldFlags =
newState.userStates[userId]!!
.appIdDevicePermissionFlags[appId]
@@ -295,20 +291,8 @@ class DevicePermissionPolicy : SchemePolicy() {
synchronized(listenersLock) { listeners = listeners + listener }
}
- private fun isDeviceAwarePermission(permissionName: String): Boolean =
- DEVICE_AWARE_PERMISSIONS.contains(permissionName)
-
companion object {
private val LOG_TAG = DevicePermissionPolicy::class.java.simpleName
-
- /** These permissions are supported for virtual devices. */
- // TODO: b/298661870 - Use new API to get the list of device aware permissions.
- val DEVICE_AWARE_PERMISSIONS =
- if (Flags.deviceAwarePermissionApisEnabled()) {
- setOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
- } else {
- emptySet<String>()
- }
}
/** Listener for permission flags changes. */
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 0f65494cde3e..f469ab547763 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -1555,7 +1555,7 @@ class PermissionService(private val service: AccessCheckingService) :
deviceId == Context.DEVICE_ID_DEFAULT) {
with(policy) { getPermissionFlags(appId, userId, permissionName) }
} else {
- if (permissionName !in DevicePermissionPolicy.DEVICE_AWARE_PERMISSIONS) {
+ if (permissionName !in DEVICE_AWARE_PERMISSIONS) {
Slog.i(
LOG_TAG,
"$permissionName is not device aware permission, " +
@@ -1591,7 +1591,7 @@ class PermissionService(private val service: AccessCheckingService) :
deviceId == Context.DEVICE_ID_DEFAULT) {
with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
} else {
- if (permissionName !in DevicePermissionPolicy.DEVICE_AWARE_PERMISSIONS) {
+ if (permissionName !in DEVICE_AWARE_PERMISSIONS) {
Slog.i(
LOG_TAG,
"$permissionName is not device aware permission, " +
@@ -2314,20 +2314,19 @@ class PermissionService(private val service: AccessCheckingService) :
override fun onSystemReady() {
service.onSystemReady()
+
virtualDeviceManagerInternal =
LocalServices.getService(VirtualDeviceManagerInternal::class.java)
-
virtualDeviceManagerInternal?.allPersistentDeviceIds?.let { persistentDeviceIds ->
service.mutateState {
- with(devicePolicy) { removeInactiveDevicesPermission(persistentDeviceIds) }
+ with(devicePolicy) { trimDevicePermissionStates(persistentDeviceIds) }
}
}
-
- // trim permission states for the external devices, when they are removed.
virtualDeviceManagerInternal?.registerPersistentDeviceIdRemovedListener { persistentDeviceId
->
service.mutateState { with(devicePolicy) { onDeviceIdRemoved(persistentDeviceId) } }
}
+
permissionControllerManager =
PermissionControllerManager(context, PermissionThread.getHandler())
}
@@ -2862,5 +2861,14 @@ class PermissionService(private val service: AccessCheckingService) :
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE or
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM or
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
+
+ /** These permissions are supported for virtual devices. */
+ // TODO: b/298661870 - Use new API to get the list of device aware permissions.
+ val DEVICE_AWARE_PERMISSIONS =
+ if (Flags.deviceAwarePermissionApisEnabled()) {
+ setOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
+ } else {
+ emptySet<String>()
+ }
}
}
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index d62da1a02525..5b222c01d56b 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -57,11 +57,11 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.core.app.ApplicationProvider;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowUserManager;
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 3011fa17d4fc..5c4716dc751e 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -25,6 +25,7 @@ import android.os.Binder
import android.os.UserHandle
import android.util.ArrayMap
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.internal.pm.pkg.component.ParsedActivity
import com.android.server.pm.AppsFilterImpl
@@ -38,7 +39,6 @@ import com.android.server.pm.Settings
import com.android.server.pm.SharedLibrariesImpl
import com.android.server.pm.UserManagerInternal
import com.android.server.pm.UserManagerService
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
@@ -49,6 +49,8 @@ import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.android.server.wm.ActivityTaskManagerInternal
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.UUID
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
@@ -61,8 +63,6 @@ import org.mockito.Mockito.doReturn
import org.mockito.Mockito.intThat
import org.mockito.Mockito.same
import org.testng.Assert.assertThrows
-import java.io.File
-import java.util.UUID
@RunWith(Parameterized::class)
class PackageManagerComponentLabelIconOverrideTest {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
index 3461bb6b2c55..7277fd79fdd5 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
@@ -49,20 +49,20 @@ import android.util.SparseArray;
import androidx.annotation.NonNull;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
+import com.android.internal.pm.pkg.component.ParsedComponentImpl;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.pm.pkg.component.ParsedPermission;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedComponentImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.server.utils.WatchableTester;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
index f0d389be7cb6..b1c3e94c2138 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
@@ -32,11 +32,11 @@ import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.platform.test.annotations.Presubmit;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.PackageStateUnserialized;
import com.android.server.pm.pkg.PackageUserStateImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import org.junit.After;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index f07e820bf8b3..40d3d5ca9fd9 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -45,15 +45,19 @@ import android.annotation.NonNull;
import android.app.PropertyInvalidatedCache;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.BaseBundle;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -63,10 +67,11 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.ArchiveState;
@@ -85,6 +90,7 @@ import com.google.common.truth.Truth;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -109,6 +115,9 @@ import java.util.concurrent.CountDownLatch;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PackageManagerSettingsTests {
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PACKAGE_NAME_1 = "com.android.app1";
private static final String PACKAGE_NAME_2 = "com.android.app2";
private static final String PACKAGE_NAME_3 = "com.android.app3";
@@ -140,6 +149,7 @@ public class PackageManagerSettingsTests {
public void setup() {
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
+
}
@Before
@@ -161,6 +171,107 @@ public class PackageManagerSettingsTests {
deleteFolder(InstrumentationRegistry.getContext().getFilesDir());
}
+ @Test
+ public void testApplicationInfoForUseSdkOptionalEnabled() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_SDK_LIB_INDEPENDENCE);
+
+ // Create basic information for SDK lib
+ final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+ ps1.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
+ .setUid(ps1.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps1.setUsesSdkLibraries(new String[] { "com.example.sdk.one" });
+ ps1.setUsesSdkLibrariesVersionsMajor(new long[] { 12 });
+ ps1.setUsesSdkLibrariesOptional(new boolean[] {true});
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path1",
+ "packageName1",
+ Collections.emptyList(),
+ "com.example.sdk.one",
+ 12 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path11",
+ "packageName11",
+ Collections.emptyList(),
+ "com.example.sdk.oneone",
+ 1212 /*version*/,
+ SharedLibraryInfo.TYPE_STATIC,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo1 = PackageInfoUtils.generateApplicationInfo(ps1.getAndroidPackage(),
+ 0 /*flags*/, ps1.getUserStateOrDefault(0), 0 /*userId*/,
+ ps1);
+ assertThat(appInfo1, notNullValue());
+ assertThat(appInfo1.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo1.optionalSharedLibraryInfos, notNullValue());
+ assertEquals(appInfo1.sharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+ assertEquals(appInfo1.optionalSharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+
+ final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+ ps2.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_2).hideAsParsed())
+ .setUid(ps2.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps2.setUsesSdkLibraries(new String[] { "com.example.sdk.two" });
+ ps2.setUsesSdkLibrariesVersionsMajor(new long[] { 34 });
+ ps2.setUsesSdkLibrariesOptional(new boolean[] {false});
+ ps2.addUsesLibraryInfo(new SharedLibraryInfo("path2",
+ "packageName2",
+ Collections.emptyList(),
+ "com.example.sdk.two",
+ 34 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo2 = PackageInfoUtils.generateApplicationInfo(ps2.getAndroidPackage(),
+ 0 /*flags*/, ps2.getUserStateOrDefault(0), 0 /*userId*/,
+ ps2);
+ assertThat(appInfo2, notNullValue());
+ assertThat(appInfo2.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo2.optionalSharedLibraryInfos, nullValue());
+ assertEquals(appInfo2.sharedLibraryInfos.get(0).getName(), "com.example.sdk.two");
+ }
+
+ @Test
+ public void testApplicationInfoForUseSdkOptionalDisabled() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_SDK_LIB_INDEPENDENCE);
+
+ // Create basic information for SDK lib
+ final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+ ps1.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
+ .setUid(ps1.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps1.setUsesSdkLibraries(new String[] { "com.example.sdk.one" });
+ ps1.setUsesSdkLibrariesVersionsMajor(new long[] { 12 });
+ ps1.setUsesSdkLibrariesOptional(new boolean[] {true});
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path1",
+ "packageName1",
+ Collections.emptyList(),
+ "com.example.sdk.one",
+ 12 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo1 = PackageInfoUtils.generateApplicationInfo(ps1.getAndroidPackage(),
+ 0 /*flags*/, ps1.getUserStateOrDefault(0), 0 /*userId*/,
+ ps1);
+ assertThat(appInfo1, notNullValue());
+ assertThat(appInfo1.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo1.optionalSharedLibraryInfos, nullValue());
+ assertEquals(appInfo1.sharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+ }
+
/** make sure our initialized KeySetManagerService metadata matches packages.xml */
@Test
public void testReadKeySetSettings() throws Exception {
@@ -315,7 +426,7 @@ public class PackageManagerSettingsTests {
PackageUserStateInternal packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -327,7 +438,7 @@ public class PackageManagerSettingsTests {
packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -362,7 +473,8 @@ public class PackageManagerSettingsTests {
watcher.verifyNoChangeReported("readUserState");
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is(PACKAGE_NAME_3));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0),
+ is(UserPackage.of(0, PACKAGE_NAME_3)));
final SuspendParams params = packageUserState1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("fetch user state");
assertThat(params, is(notNullValue()));
@@ -413,19 +525,24 @@ public class PackageManagerSettingsTests {
.setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND)
.build();
- ps1.modifyUserState(0).putSuspendParams("suspendingPackage1",
+ UserPackage suspender1 = UserPackage.of(0, "suspendingPackage1");
+ UserPackage suspender2 = UserPackage.of(0, "suspendingPackage2");
+ UserPackage suspender3 = UserPackage.of(0, "suspendingPackage3");
+ UserPackage irrelevantSuspender = UserPackage.of(0, "irrelevant");
+
+ ps1.modifyUserState(0).putSuspendParams(suspender1,
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
- ps1.modifyUserState(0).putSuspendParams("suspendingPackage2",
+ ps1.modifyUserState(0).putSuspendParams(suspender2,
new SuspendParams(dialogInfo2, appExtras2, launcherExtras2));
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
watcher.verifyChangeReported("put package 1");
- ps2.modifyUserState(0).putSuspendParams("suspendingPackage3",
+ ps2.modifyUserState(0).putSuspendParams(suspender3,
new SuspendParams(null, appExtras1, null));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
watcher.verifyChangeReported("put package 2");
- ps3.modifyUserState(0).removeSuspension("irrelevant");
+ ps3.modifyUserState(0).removeSuspension(irrelevantSuspender);
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
watcher.verifyChangeReported("put package 3");
@@ -450,7 +567,7 @@ public class PackageManagerSettingsTests {
assertThat(readPus1.getSuspendParams().size(), is(2));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(0), is("suspendingPackage1"));
+ assertThat(readPus1.getSuspendParams().keyAt(0), is(suspender1));
final SuspendParams params11 = readPus1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("read package param");
assertThat(params11, is(notNullValue()));
@@ -460,7 +577,7 @@ public class PackageManagerSettingsTests {
is(true));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2"));
+ assertThat(readPus1.getSuspendParams().keyAt(1), is(suspender2));
final SuspendParams params12 = readPus1.getSuspendParams().valueAt(1);
assertThat(params12, is(notNullValue()));
assertThat(params12.getDialogInfo(), is(dialogInfo2));
@@ -473,7 +590,7 @@ public class PackageManagerSettingsTests {
.readUserState(0);
assertThat(readPus2.isSuspended(), is(true));
assertThat(readPus2.getSuspendParams().size(), is(1));
- assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3"));
+ assertThat(readPus2.getSuspendParams().keyAt(0), is(suspender3));
final SuspendParams params21 = readPus2.getSuspendParams().valueAt(0);
assertThat(params21, is(notNullValue()));
assertThat(params21.getDialogInfo(), is(nullValue()));
@@ -1024,7 +1141,8 @@ public class PackageManagerSettingsTests {
.setNeutralButtonText(0x11220003)
.setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS)
.build();
- origPkgSetting01.modifyUserState(0).putSuspendParams("suspendingPackage1",
+ origPkgSetting01.modifyUserState(0).putSuspendParams(
+ UserPackage.of(0, "suspendingPackage1"),
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
origPkgSetting01.setPkg(mockAndroidPackage(origPkgSetting01));
final PackageSetting testPkgSetting01 = new PackageSetting(
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index 9c48af8ecd01..285c059e973a 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -73,7 +73,7 @@ import androidx.test.filters.Suppress;
import com.android.compatibility.common.util.CddTest;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.parsing.ParsingUtils;
import com.android.server.pm.test.service.server.R;
import dalvik.system.VMRuntime;
@@ -346,7 +346,7 @@ public class PackageManagerTests extends AndroidTestCase {
private ParsedPackage parsePackage(Uri packageURI) {
final String archiveFilePath = packageURI.getPath();
- ParseResult<ParsedPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ ParseResult<ParsedPackage> result = ParsingUtils.parseDefaultOneTime(
new File(archiveFilePath), 0 /*flags*/, Collections.emptyList(),
false /*collectCertificates*/);
if (result.isError()) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index a62cd4fc5fc2..03e45a27390f 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -15,7 +15,7 @@
*/
package com.android.server.pm;
-import static com.android.server.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
+import static com.android.internal.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -58,17 +58,28 @@ import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceImpl;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.parsing.PackageCacher;
@@ -76,19 +87,8 @@ import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.permission.CompatibilityPermissionInfo;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedServiceImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import org.junit.Before;
import org.junit.Rule;
@@ -725,6 +725,16 @@ public class PackageParserTest {
public boolean hasFeature(String feature) {
return false;
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return new ArraySet<>();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return new ArraySet<>();
+ }
});
if (cacheDir != null) {
setCacheDir(cacheDir);
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
index c0c70321c79b..978044045ab3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.PersistableBundle;
import android.platform.test.annotations.Presubmit;
@@ -89,7 +90,7 @@ public class PackageUserStateTest {
assertThat(testUserState.equals(oldUserState), is(false));
oldUserState = new PackageUserStateImpl();
- oldUserState.putSuspendParams("suspendingPackage",
+ oldUserState.putSuspendParams(UserPackage.of(0, "suspendingPackage"),
new SuspendParams(null, new PersistableBundle(), null));
assertThat(testUserState.equals(oldUserState), is(false));
@@ -220,6 +221,8 @@ public class PackageUserStateTest {
final PersistableBundle launcherExtras2 = createPersistableBundle(null, 0, "name",
"launcherExtras2", null, 0);
+ final int suspendingUser1 = 0;
+ final int suspendingUser2 = 10;
final String suspendingPackage1 = "package1";
final String suspendingPackage2 = "package2";
@@ -230,12 +233,12 @@ public class PackageUserStateTest {
.setMessage("dialogMessage2")
.build();
- final ArrayMap<String, SuspendParams> paramsMap1 = new ArrayMap<>();
- paramsMap1.put(suspendingPackage1, createSuspendParams(dialogInfo1, appExtras1,
- launcherExtras1));
- final ArrayMap<String, SuspendParams> paramsMap2 = new ArrayMap<>();
- paramsMap2.put(suspendingPackage2, createSuspendParams(dialogInfo2,
- appExtras2, launcherExtras2));
+ final ArrayMap<UserPackage, SuspendParams> paramsMap1 = new ArrayMap<>();
+ paramsMap1.put(UserPackage.of(suspendingUser1, suspendingPackage1),
+ createSuspendParams(dialogInfo1, appExtras1, launcherExtras1));
+ final ArrayMap<UserPackage, SuspendParams> paramsMap2 = new ArrayMap<>();
+ paramsMap2.put(UserPackage.of(suspendingUser2, suspendingPackage2),
+ createSuspendParams(dialogInfo2, appExtras2, launcherExtras2));
final PackageUserStateImpl testUserState1 = new PackageUserStateImpl();
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
index 6202908cdfbf..c1271bb0ee36 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
@@ -50,13 +50,13 @@ import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import org.hamcrest.BaseMatcher;
@@ -376,7 +376,7 @@ public class ScanTests {
// Create the ParsedPackage for the apex
final ParsedPackage basicPackage =
((ParsedPackage) new PackageImpl(DUMMY_PACKAGE_NAME, codePath, codePath,
- mock(TypedArray.class), false)
+ mock(TypedArray.class), false, null)
.setVolumeUuid(UUID_ONE.toString())
.hideAsParsed())
.setVersionCodeMajor(1)
@@ -595,7 +595,7 @@ public class ScanTests {
// TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
return (ParsingPackage) ((ParsedPackage) new PackageImpl(packageName,
"/data/tmp/randompath/base.apk", createCodePath(packageName),
- mock(TypedArray.class), false)
+ mock(TypedArray.class), false, null)
.setVolumeUuid(UUID_ONE.toString())
.addUsesStaticLibrary("some.static.library", 234L, new String[]{"testCert1"})
.addUsesStaticLibrary("some.other.static.library", 456L, new String[]{"testCert2"})
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index b102ab4f7e3b..b63950c10a18 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -39,14 +39,14 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ParsedActivityUtils;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedActivityUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
import com.android.server.pm.test.service.server.R;
import com.google.common.truth.Expect;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index 67b91d2646d9..c435b94fcacd 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -22,7 +22,6 @@ import android.content.pm.parsing.result.ParseResult
import android.platform.test.annotations.Presubmit
import androidx.test.InstrumentationRegistry
import com.android.internal.pm.parsing.pkg.ParsedPackage
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.test.service.server.R
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
@@ -121,7 +120,7 @@ class PackageParsingDeferErrorTest {
input.copyTo(output)
}
}
- return ParsingPackageUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(),
+ return ParsingUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(),
false /*collectCertificates*/)
}
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java
new file mode 100644
index 000000000000..a9eac95dfd87
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java
@@ -0,0 +1,81 @@
+/*
+ * 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.pm.parsing;
+
+import android.annotation.NonNull;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.res.TypedArray;
+import android.permission.PermissionManager;
+
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.SystemConfig;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+/** @hide **/
+public class ParsingUtils {
+
+ /**
+ * @see ParsingPackageUtils#parseDefault(ParseInput, File, int, List, boolean,
+ * ParsingPackageUtils.Callback)
+ */
+ @NonNull
+ public static ParseResult<ParsedPackage> parseDefaultOneTime(File file,
+ @ParsingPackageUtils.ParseFlags int parseFlags,
+ @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
+ boolean collectCertificates) {
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
+ return ParsingPackageUtils.parseDefault(input, file, parseFlags, splitPermissions, collectCertificates,
+ new ParsingPackageUtils.Callback() {
+ @Override
+ public boolean hasFeature(String feature) {
+ // Assume the device doesn't support anything. This will affect permission
+ // parsing and will force <uses-permission/> declarations to include all
+ // requiredNotFeature permissions and exclude all requiredFeature
+ // permissions. This mirrors the old behavior.
+ return false;
+ }
+
+ @Override
+ public ParsingPackage startParsingPackage(
+ @NonNull String packageName,
+ @NonNull String baseApkPath,
+ @NonNull String path,
+ @NonNull TypedArray manifestArray, boolean isCoreApp) {
+ return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray,
+ isCoreApp, this);
+ }
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
+ });
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
index 1f57b6c9f95f..98af63c65e90 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
@@ -17,15 +17,15 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import android.platform.test.annotations.Postsubmit
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.PackageManagerException
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageManagerServiceUtils
+import java.io.File
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
-import java.io.File
/**
* This test parses all the system APKs on the device image to ensure that they succeed.
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
index 6cd71237efa2..9517e49c4a73 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -24,8 +24,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
index 27fd781584f2..01fad8f57d16 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
@@ -21,8 +21,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
index b13d6de55cf6..b1f26c253043 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -23,8 +23,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
index fa69f844c33a..349763ae18b3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -24,9 +24,9 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
index 856013a96017..71bdacbce9f7 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
@@ -22,9 +22,9 @@ import android.util.ArrayMap;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
index ae5ea21aec4e..6aa0c2db4d39 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
@@ -21,8 +21,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
index e126ffcab5ff..44098d0be2b2 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -23,8 +23,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index d0b0cf894340..9d5ce8a66395 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -28,10 +28,10 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Assume;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index c141c0337540..bffeb7255b31 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -23,9 +23,9 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index a58604b81e06..b114cd375050 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -23,9 +23,9 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 09b66c11d200..ef9c62fd3795 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -30,21 +30,21 @@ import android.util.ArraySet
import android.util.SparseArray
import android.util.SparseIntArray
import com.android.internal.R
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils
-import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils
+import com.android.internal.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
+import com.android.internal.pm.pkg.component.ParsedServiceImpl
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl
-import com.android.server.pm.pkg.component.ParsedAttributionImpl
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
-import com.android.server.pm.pkg.component.ParsedProcessImpl
-import com.android.server.pm.pkg.component.ParsedProviderImpl
-import com.android.server.pm.pkg.component.ParsedServiceImpl
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import java.security.KeyPairGenerator
@@ -534,34 +534,34 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
}
),
getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
- getSetByValue({ AndroidPackageUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true),
- getSetByValue({ AndroidPackageUtils.isOem(it) }, "isOem", PackageImpl::setOem, true),
+ getSetByValue({ AndroidPackageLegacyUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true),
+ getSetByValue({ AndroidPackageLegacyUtils.isOem(it) }, "isOem", PackageImpl::setOem, true),
getSetByValue(
- { AndroidPackageUtils.isPrivileged(it) },
+ { AndroidPackageLegacyUtils.isPrivileged(it) },
"isPrivileged",
PackageImpl::setPrivileged,
true
),
getSetByValue(
- { AndroidPackageUtils.isProduct(it) },
+ { AndroidPackageLegacyUtils.isProduct(it) },
"isProduct",
PackageImpl::setProduct,
true
),
getSetByValue(
- { AndroidPackageUtils.isVendor(it) },
+ { AndroidPackageLegacyUtils.isVendor(it) },
"isVendor",
PackageImpl::setVendor,
true
),
getSetByValue(
- { AndroidPackageUtils.isSystem(it) },
+ { AndroidPackageLegacyUtils.isSystem(it) },
"isSystem",
PackageImpl::setSystem,
true
),
getSetByValue(
- { AndroidPackageUtils.isSystemExt(it) },
+ { AndroidPackageLegacyUtils.isSystemExt(it) },
"isSystemExt",
PackageImpl::setSystemExt,
true
@@ -593,7 +593,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
)
) { "" }
},
- true
+ true, null
)
.asSplit(
arrayOf("testSplitNameZero", "testSplitNameOne"),
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
index 26468544e8d6..2c8b1cd884f1 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
@@ -18,7 +18,7 @@ package com.android.server.pm.test.parsing.parcelling
import android.content.pm.ActivityInfo
import com.android.internal.pm.pkg.component.ParsedActivity
-import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
index 52d5b3bccb72..ad5374672d22 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedAttribution
-import com.android.server.pm.pkg.component.ParsedAttributionImpl
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
index af0c0de2db15..3ac48536b39c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
@@ -18,8 +18,8 @@ package com.android.server.pm.test.parsing.parcelling
import android.content.pm.PackageManager
import com.android.internal.pm.pkg.component.ParsedComponent
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Bundle
import android.os.Parcelable
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
index dc0f194f10cc..2bd4f617dcb5 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedInstrumentation
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
index 5224f23d38d1..af385e202a9e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedIntentInfo
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Parcelable
import android.os.PatternMatcher
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
index dfff6025e2eb..061e39ddf6df 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedMainComponent
-import com.android.server.pm.pkg.component.ParsedMainComponentImpl
+import com.android.internal.pm.pkg.component.ParsedMainComponentImpl
import android.os.Parcelable
import java.util.Arrays
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
index ccbf558734d3..3a6418824dfa 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
index 2814783b6849..551f16d2a3bb 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
@@ -18,8 +18,8 @@ package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedPermission
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
index 2e9604696acb..93bdeaeb90e3 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
@@ -16,9 +16,9 @@
package com.android.server.pm.test.parsing.parcelling
-import com.android.internal.pm.pkg.component.ParsedProcess
-import com.android.server.pm.pkg.component.ParsedProcessImpl
import android.util.ArrayMap
+import com.android.internal.pm.pkg.component.ParsedProcess
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
index 290dbd6277b6..1e844705fe3c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
@@ -17,9 +17,9 @@
package com.android.server.pm.test.parsing.parcelling
import android.content.pm.PathPermission
-import com.android.internal.pm.pkg.component.ParsedProvider
-import com.android.server.pm.pkg.component.ParsedProviderImpl
import android.os.PatternMatcher
+import com.android.internal.pm.pkg.component.ParsedProvider
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
index 3ae7e9220cc6..79d5a4f7030a 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedService
-import com.android.server.pm.pkg.component.ParsedServiceImpl
+import com.android.internal.pm.pkg.component.ParsedServiceImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
index 67dfc6d4f7ef..d0ad09be982b 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedUsesPermission
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
index 1da3a2234ffc..b21c34905bad 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
@@ -17,37 +17,34 @@
package com.android.server.pm.test.pkg
import android.content.Intent
-import android.content.pm.overlay.OverlayPaths
import android.content.pm.PackageManager
import android.content.pm.PathPermission
import android.content.pm.SharedLibraryInfo
import android.content.pm.VersionedPackage
+import android.content.pm.overlay.OverlayPaths
import android.os.PatternMatcher
import android.util.ArraySet
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.pkg.component.ParsedActivity
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
import com.android.internal.pm.pkg.component.ParsedInstrumentation
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.internal.pm.pkg.component.ParsedPermission
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
import com.android.internal.pm.pkg.component.ParsedProcess
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
import com.android.internal.pm.pkg.component.ParsedProvider
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
import com.android.internal.pm.pkg.component.ParsedService
import com.android.server.pm.PackageSetting
import com.android.server.pm.PackageSettingBuilder
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
import com.android.server.pm.pkg.PackageUserState
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
-import com.android.server.pm.pkg.component.ParsedProcessImpl
-import com.android.server.pm.pkg.component.ParsedProviderImpl
import com.android.server.pm.test.parsing.parcelling.AndroidPackageTest
import com.google.common.truth.Expect
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
import kotlin.contracts.ExperimentalContracts
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
@@ -55,6 +52,9 @@ import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.starProjectedType
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
class PackageStateTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index 9341e9d96335..5e73d198f528 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -22,11 +22,11 @@ import android.os.Build
import android.os.PatternMatcher
import android.util.ArraySet
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.SystemConfig
import com.android.server.compat.PlatformCompat
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationCollector
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index a737b9097b53..d307608e0be2 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -29,17 +29,22 @@ import android.util.IndentingPrintWriter
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.Computer
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationEnforcer
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
+import java.util.UUID
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicInteger
+import kotlin.test.assertFailsWith
+import kotlin.test.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -51,11 +56,6 @@ import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.verifyNoMoreInteractions
-import java.util.UUID
-import java.util.concurrent.atomic.AtomicBoolean
-import java.util.concurrent.atomic.AtomicInteger
-import kotlin.test.assertFailsWith
-import kotlin.test.fail
@RunWith(Parameterized::class)
class DomainVerificationEnforcerTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index f38df22af630..5edf30a33def 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -30,24 +30,24 @@ import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationManagerStub
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
+import java.util.concurrent.atomic.AtomicBoolean
+import kotlin.test.assertFailsWith
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.util.UUID
-import java.util.concurrent.atomic.AtomicBoolean
-import kotlin.test.assertFailsWith
class DomainVerificationManagerApiTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index 874e0d2bbc9a..85f012534113 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -37,27 +37,27 @@ import android.util.ArraySet
import android.util.SparseArray
import android.util.Xml
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.Computer
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mock
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.spy
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.security.PublicKey
+import java.util.UUID
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.io.ByteArrayInputStream
-import java.io.ByteArrayOutputStream
-import java.security.PublicKey
-import java.util.UUID
class DomainVerificationPackageTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 3207e6c2a411..a5c4f6cc0289 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -25,15 +25,16 @@ import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
+import java.util.UUID
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -44,7 +45,6 @@ import org.mockito.Mockito.anyString
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.verify
-import java.util.UUID
@RunWith(Parameterized::class)
class DomainVerificationSettingsMutationTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index a90b7d5ec7da..ae570a3a0ee2 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -27,14 +27,15 @@ import android.os.Process
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
@@ -42,8 +43,6 @@ import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.util.UUID
-
class DomainVerificationUserStateOverrideTest {
companion object {
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt
index 832136cec792..925dad8b6661 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt
@@ -38,7 +38,7 @@ import org.junit.runners.Parameterized
* AppIdPermissionPolicyPermissionStatesTest because these concepts don't apply to onUserAdded().
*/
@RunWith(Parameterized::class)
-class AppIdPermissionPolicyPermissionDefinitionsTest : BaseAppIdPermissionPolicyTest() {
+class AppIdPermissionPolicyPermissionDefinitionsTest : BasePermissionPolicyTest() {
@Parameterized.Parameter(0) lateinit var action: Action
@Test
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
index 05477197b991..12370954e9a5 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
@@ -29,7 +29,7 @@ import org.junit.runners.Parameterized
* and resetRuntimePermissions() in AppIdPermissionPolicy
*/
@RunWith(Parameterized::class)
-class AppIdPermissionPolicyPermissionResetTest : BaseAppIdPermissionPolicyTest() {
+class AppIdPermissionPolicyPermissionResetTest : BasePermissionPolicyTest() {
@Parameterized.Parameter(0) lateinit var action: Action
@Test
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
index c44b2c50258e..6b9c9c2b4abc 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* states for onUserAdded(), onStorageVolumeAdded() and onPackageAdded() in AppIdPermissionPolicy
*/
@RunWith(Parameterized::class)
-class AppIdPermissionPolicyPermissionStatesTest : BaseAppIdPermissionPolicyTest() {
+class AppIdPermissionPolicyPermissionStatesTest : BasePermissionPolicyTest() {
@Parameterized.Parameter(0) lateinit var action: Action
@Before
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
index e4e336845fca..cde46abafe95 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
@@ -30,7 +30,7 @@ import org.junit.Test
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-class AppIdPermissionPolicyTest : BaseAppIdPermissionPolicyTest() {
+class AppIdPermissionPolicyTest : BasePermissionPolicyTest() {
@Test
fun testOnAppIdRemoved_appIdIsRemoved_permissionFlagsCleared() {
val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0)
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BasePermissionPolicyTest.kt
index 316f3387c539..7b3f21603c0a 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BasePermissionPolicyTest.kt
@@ -53,7 +53,7 @@ import org.mockito.ArgumentMatchers.anyLong
* Mocking unit test for AppIdPermissionPolicy.
*/
@RunWith(AndroidJUnit4::class)
-abstract class BaseAppIdPermissionPolicyTest {
+abstract class BasePermissionPolicyTest {
protected lateinit var oldState: MutableAccessState
protected lateinit var newState: MutableAccessState
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/DevicePermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/DevicePermissionPolicyTest.kt
new file mode 100644
index 000000000000..996dd9dcba4b
--- /dev/null
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/DevicePermissionPolicyTest.kt
@@ -0,0 +1,282 @@
+/*
+ * 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.permission.test
+
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutableAccessState
+import com.android.server.permission.access.MutableDevicePermissionFlags
+import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
+import com.android.server.permission.access.permission.DevicePermissionPolicy
+import com.android.server.permission.access.permission.PermissionFlags
+import com.android.server.testutils.mock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+/**
+ * This class tests permissions for external devices, we have separate policy to
+ * manage external device permissions.
+ */
+class DevicePermissionPolicyTest : BasePermissionPolicyTest() {
+ private val devicePermissionPolicy = DevicePermissionPolicy()
+
+ @Test
+ fun testOnAppIdRemoved_clearPermissionFlags() {
+ val packageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+ )
+ addPackageState(packageState)
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED
+ )
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+
+ mutateState {
+ with(devicePermissionPolicy) {
+ onAppIdRemoved(APP_ID_1)
+ }
+ }
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0))
+ .isEqualTo(0)
+ }
+
+ @Test
+ fun testOnDeviceIdRemoved_clearPermissionFlags() {
+ val requestingPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+ )
+ addPackageState(requestingPackageState)
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED
+ )
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_2, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED
+ )
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_2, USER_ID_0, PERMISSION_NAME_0, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+
+ mutateState {
+ with(devicePermissionPolicy) {
+ onDeviceIdRemoved(DEVICE_ID_1)
+ }
+ }
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0))
+ .isEqualTo(0)
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_2, USER_ID_0, PERMISSION_NAME_0))
+ .isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ }
+
+ @Test
+ fun testRemoveInactiveDevicesPermission_clearPermissionFlags() {
+ val requestingPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+ )
+ addPackageState(requestingPackageState)
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED
+ )
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_2, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED
+ )
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_2, USER_ID_0, PERMISSION_NAME_0, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+
+ mutateState {
+ with(devicePermissionPolicy) {
+ trimDevicePermissionStates(setOf(DEVICE_ID_2))
+ }
+ }
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0))
+ .isEqualTo(0)
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_2, USER_ID_0, PERMISSION_NAME_0))
+ .isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ }
+
+ @Test
+ fun testOnStateMutated_notEmpty_isCalledForEachListener() {
+ val mockListener =
+ mock<DevicePermissionPolicy.OnDevicePermissionFlagsChangedListener> {}
+ devicePermissionPolicy.addOnPermissionFlagsChangedListener(mockListener)
+
+ GetStateScope(oldState).apply {
+ with(devicePermissionPolicy) {
+ onStateMutated()
+ }
+ }
+
+ verify(mockListener, times(1)).onStateMutated()
+ }
+
+ @Test
+ fun testOnStorageVolumeMounted_trimsPermissionsNotRequestAnymore() {
+ val packageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(
+ PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_1, PERMISSION_NAME_0)
+ )
+ )
+ addPackageState(packageState)
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1, PermissionFlags.RUNTIME_GRANTED
+ )
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED
+ )
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+
+ val installedPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_1))
+ )
+ addPackageState(installedPackageState)
+
+ mutateState {
+ with(devicePermissionPolicy) {
+ onStorageVolumeMounted(null, listOf(PACKAGE_NAME_1), false)
+ }
+ }
+
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1))
+ .isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0))
+ .isEqualTo(0)
+ }
+
+
+ @Test
+ fun testResetRuntimePermissions_trimsPermissionStates() {
+ val packageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_1))
+ )
+ addPackageState(packageState)
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1, PermissionFlags.RUNTIME_GRANTED
+ )
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+
+ mutateState {
+ with(devicePermissionPolicy) {
+ resetRuntimePermissions(PACKAGE_NAME_1, USER_ID_0)
+ }
+ }
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1))
+ .isEqualTo(0)
+ }
+
+ @Test
+ fun testResetRuntimePermissions_keepsPermissionStates() {
+ val packageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(
+ PACKAGE_NAME_1,
+ requestedPermissions = setOf(PERMISSION_NAME_1, PERMISSION_NAME_0)
+ )
+ )
+ val packageState2 = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_2, requestedPermissions = setOf(PERMISSION_NAME_0))
+ )
+ addPackageState(packageState)
+ addPackageState(packageState2)
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1, PermissionFlags.RUNTIME_GRANTED
+ )
+ setPermissionFlags(
+ APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED
+ )
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ assertThat(
+ getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0, oldState)
+ ).isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+
+ mutateState {
+ with(devicePermissionPolicy) {
+ resetRuntimePermissions(PACKAGE_NAME_1, USER_ID_0)
+ }
+ }
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_1))
+ .isEqualTo(0)
+ assertThat(getPermissionFlags(APP_ID_1, DEVICE_ID_1, USER_ID_0, PERMISSION_NAME_0))
+ .isEqualTo(PermissionFlags.RUNTIME_GRANTED)
+ }
+
+ private fun getPermissionFlags(
+ appId: Int,
+ deviceId: String,
+ userId: Int,
+ permissionName: String,
+ state: MutableAccessState = newState
+ ): Int = state.userStates[userId]
+ ?.appIdDevicePermissionFlags
+ ?.get(appId)
+ ?.get(deviceId)
+ ?.getWithDefault(permissionName, 0)
+ ?: 0
+
+
+ private fun setPermissionFlags(
+ appId: Int,
+ deviceId: String,
+ userId: Int,
+ permissionName: String,
+ newFlags: Int,
+ state: MutableAccessState = oldState
+ ) {
+ val appIdDevicePermissionFlags =
+ state.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
+ val devicePermissionFlags =
+ appIdDevicePermissionFlags.mutateOrPut(appId) { MutableDevicePermissionFlags() }
+ val permissionFlags =
+ devicePermissionFlags.mutateOrPut(deviceId) { MutableIndexedMap() }
+ permissionFlags.putWithDefault(permissionName, newFlags, 0)
+ if (permissionFlags.isEmpty()) {
+ devicePermissionFlags -= deviceId
+ if (devicePermissionFlags.isEmpty()) {
+ appIdDevicePermissionFlags -= appId
+ }
+ }
+ }
+
+ companion object {
+ private const val DEVICE_ID_1 = "cdm:1"
+ private const val DEVICE_ID_2 = "cdm:2"
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
new file mode 100644
index 000000000000..ebb4f1889cd6
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.display.mode
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.provider.Settings
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.internal.util.test.FakeSettingsProvider
+import com.android.server.display.feature.DisplayManagerFlags
+import com.android.server.testutils.TestHandler
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class SettingsObserverTest {
+
+ @get:Rule
+ val mockitoRule = MockitoJUnit.rule()
+
+ @get:Rule
+ val settingsProviderRule = FakeSettingsProvider.rule()
+
+ private lateinit var spyContext: Context
+ private val mockInjector = mock<DisplayModeDirector.Injector>()
+ private val mockFlags = mock<DisplayManagerFlags>()
+
+ private val testHandler = TestHandler(null)
+
+ @Before
+ fun setUp() {
+ spyContext = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+ }
+
+ @Test
+ fun testLowPowerMode(@TestParameter testCase: SettingsObserverTestCase) {
+ whenever(mockFlags.isVsyncLowPowerVoteEnabled).thenReturn(testCase.vsyncLowPowerVoteEnabled)
+ whenever(spyContext.contentResolver)
+ .thenReturn(settingsProviderRule.mockContentResolver(null))
+ val lowPowerModeSetting = if (testCase.lowPowerModeEnabled) 1 else 0
+ Settings.Global.putInt(
+ spyContext.contentResolver, Settings.Global.LOW_POWER_MODE, lowPowerModeSetting)
+
+ val displayModeDirector = DisplayModeDirector(
+ spyContext, testHandler, mockInjector, mockFlags)
+ val settingsObserver = displayModeDirector.SettingsObserver(
+ spyContext, testHandler, testCase.dvrrSupported, mockFlags)
+
+ settingsObserver.onChange(
+ false, Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), 1)
+
+ assertThat(displayModeDirector.getVote(VotesStorage.GLOBAL_ID,
+ Vote.PRIORITY_LOW_POWER_MODE)).isEqualTo(testCase.expectedVote)
+ }
+
+ enum class SettingsObserverTestCase(
+ val dvrrSupported: Boolean,
+ val vsyncLowPowerVoteEnabled: Boolean,
+ val lowPowerModeEnabled: Boolean,
+ internal val expectedVote: Vote?
+ ) {
+ ALL_ENABLED(true, true, true,
+ SupportedModesVote(listOf(
+ SupportedModesVote.SupportedMode(60f, 240f),
+ SupportedModesVote.SupportedMode(60f, 60f)
+ ))),
+ LOW_POWER_OFF(true, true, false, null),
+ DVRR_NOT_SUPPORTED_LOW_POWER_ON(false, true, true,
+ RefreshRateVote.RenderVote(0f, 60f)),
+ DVRR_NOT_SUPPORTED_LOW_POWER_OFF(false, true, false, null),
+ VSYNC_VOTE_DISABLED_SUPPORTED_LOW_POWER_ON(true, false, true,
+ RefreshRateVote.RenderVote(0f, 60f)),
+ VSYNC_VOTE_DISABLED_LOW_POWER_OFF(true, false, false, null),
+ }
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 820e44fd2ff7..0fd424b89837 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -334,6 +334,7 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
final boolean dead = (behavior == ProcessBehavior.DEAD);
final ProcessRecord r = spy(new ProcessRecord(mAms, ai, processName, ai.uid));
+ r.mState = spy(r.mState);
r.setPid(mNextPid.getAndIncrement());
mActiveProcesses.add(r);
@@ -788,8 +789,8 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
}) {
// Confirm expected OOM adjustments; we were invoked once to upgrade
// and once to downgrade
- assertEquals(String.valueOf(receiverApp), ActivityManager.PROCESS_STATE_RECEIVER,
- receiverApp.mState.getReportedProcState());
+ verify(receiverApp.mState, times(1).description(String.valueOf(receiverApp)))
+ .setReportedProcState(ActivityManager.PROCESS_STATE_RECEIVER);
verify(mAms, times(2)).enqueueOomAdjTargetLocked(eq(receiverApp));
if ((mImpl == Impl.DEFAULT) && (receiverApp == receiverBlueApp)) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 6906decec9a2..9739e4b46063 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -18,7 +18,10 @@ package com.android.server.app;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.server.app.GameManagerService.CANCEL_GAME_LOADING_MODE;
+import static com.android.server.app.GameManagerService.Injector;
import static com.android.server.app.GameManagerService.LOADING_BOOST_MAX_DURATION;
+import static com.android.server.app.GameManagerService.PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED;
+import static com.android.server.app.GameManagerService.PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE;
import static com.android.server.app.GameManagerService.SET_GAME_STATE;
import static com.android.server.app.GameManagerService.WRITE_DELAY_MILLIS;
import static com.android.server.app.GameManagerService.WRITE_GAME_MODE_INTERVENTION_LIST_FILE;
@@ -33,6 +36,7 @@ import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
@@ -72,9 +76,12 @@ import android.os.IBinder;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.test.FakePermissionEnforcer;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
+import android.server.app.Flags;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -85,6 +92,7 @@ import com.android.server.SystemService;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -108,6 +116,7 @@ import java.util.function.Supplier;
@Presubmit
public class GameManagerServiceTests {
@Mock MockContext mMockContext;
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String TAG = "GameManagerServiceTests";
private static final String PACKAGE_NAME_INVALID = "com.android.app";
private static final int USER_ID_1 = 1001;
@@ -126,6 +135,11 @@ public class GameManagerServiceTests {
private UserManager mMockUserManager;
private BroadcastReceiver mShutDownActionReceiver;
+ private FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
+
+ @Mock
+ private GameManagerServiceSystemPropertiesWrapper mSysPropsMock;
+
@Captor
ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor;
@@ -193,6 +207,8 @@ public class GameManagerServiceTests {
switch (name) {
case Context.USER_SERVICE:
return mMockUserManager;
+ case Context.PERMISSION_ENFORCER_SERVICE:
+ return mFakePermissionEnforcer;
}
throw new UnsupportedOperationException("Couldn't find system service: " + name);
}
@@ -222,6 +238,8 @@ public class GameManagerServiceTests {
when(mMockPackageManager.getPackageUidAsUser(mPackageName, USER_ID_1)).thenReturn(
DEFAULT_PACKAGE_UID);
LocalServices.addService(PowerManagerInternal.class, mMockPowerManager);
+
+ mSetFlagsRule.enableFlags(Flags.FLAG_GAME_DEFAULT_FRAME_RATE);
}
private void mockAppCategory(String packageName, @ApplicationInfo.Category int category)
@@ -1695,9 +1713,8 @@ public class GameManagerServiceTests {
mockModifyGameModeGranted();
final Context context = InstrumentationRegistry.getContext();
GameManagerService gameManagerService =
- new GameManagerService(mMockContext,
- mTestLooper.getLooper(),
- context.getFilesDir());
+ new GameManagerService(mMockContext, mTestLooper.getLooper(), context.getFilesDir(),
+ new Injector());
startUser(gameManagerService, USER_ID_1);
startUser(gameManagerService, USER_ID_2);
@@ -1786,7 +1803,7 @@ public class GameManagerServiceTests {
mockDeviceConfigBattery();
final Context context = InstrumentationRegistry.getContext();
GameManagerService gameManagerService = new GameManagerService(mMockContext,
- mTestLooper.getLooper(), context.getFilesDir());
+ mTestLooper.getLooper(), context.getFilesDir(), new Injector());
startUser(gameManagerService, USER_ID_1);
startUser(gameManagerService, USER_ID_2);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
@@ -1962,7 +1979,7 @@ public class GameManagerServiceTests {
assertTrue(
gameManagerService.mHandler.hasEqualMessages(WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
USER_ID_1));
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(60.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_CUSTOM, 60);
@@ -2035,7 +2052,7 @@ public class GameManagerServiceTests {
mTestLooper.getLooper()));
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(90.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
@@ -2044,7 +2061,7 @@ public class GameManagerServiceTests {
when(DeviceConfig.getProperty(anyString(), anyString()))
.thenReturn(configStringAfter);
gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(0.0f));
}
@@ -2061,14 +2078,14 @@ public class GameManagerServiceTests {
mTestLooper.getLooper()));
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(90.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
mockInterventionsDisabledNoOptInFromXml();
gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(0.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 0);
@@ -2087,14 +2104,14 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(90.0f));
checkFps(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, 90);
mockInterventionsEnabledAllOptInFromXml();
gameManagerService.updateConfigsForUser(USER_ID_1, false, mPackageName);
- Mockito.verify(gameManagerService).setOverrideFrameRate(
+ Mockito.verify(gameManagerService).setGameModeFrameRateOverride(
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(0.0f));
}
@@ -2390,4 +2407,140 @@ public class GameManagerServiceTests {
DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, false);
}
+
+ @Test
+ public void testGameDefaultFrameRate_FlagOn() throws Exception {
+ mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_GAME_MODE);
+
+ GameManagerService gameManagerService = Mockito.spy(
+ new GameManagerService(mMockContext, mTestLooper.getLooper(),
+ InstrumentationRegistry.getContext().getFilesDir(),
+ new Injector(){
+ @Override
+ public GameManagerServiceSystemPropertiesWrapper
+ createSystemPropertiesWrapper() {
+ return mSysPropsMock;
+ }
+ }));
+
+ when(mSysPropsMock.getInt(
+ ArgumentMatchers.eq(PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE),
+ anyInt())).thenReturn(60);
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(true);
+ gameManagerService.onBootCompleted();
+
+ // Set up a game in the foreground.
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+
+ // Toggle game default frame rate on.
+ gameManagerService.toggleGameDefaultFrameRate(true);
+
+ // Verify that:
+ // 1) The system property is set correctly
+ // 2) setDefaultFrameRateOverride is called with correct arguments
+ Mockito.verify(mSysPropsMock).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq("true"));
+ Mockito.verify(gameManagerService, times(1))
+ .setGameDefaultFrameRateOverride(ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
+ ArgumentMatchers.eq(60.0f));
+
+ // Adding another game to the foreground.
+ String anotherGamePkg = "another.game";
+ String[] packages2 = {anotherGamePkg};
+ mockAppCategory(anotherGamePkg, ApplicationInfo.CATEGORY_GAME);
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+
+ // Toggle game default frame rate off.
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(false);
+ gameManagerService.toggleGameDefaultFrameRate(false);
+
+ // Verify that:
+ // 1) The system property is set correctly
+ // 2) setDefaultFrameRateOverride is called with correct arguments
+ Mockito.verify(mSysPropsMock).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq("false"));
+ Mockito.verify(gameManagerService).setGameDefaultFrameRateOverride(
+ ArgumentMatchers.eq(DEFAULT_PACKAGE_UID), ArgumentMatchers.eq(0.0f));
+ Mockito.verify(gameManagerService).setGameDefaultFrameRateOverride(
+ ArgumentMatchers.eq(somePackageId), ArgumentMatchers.eq(0.0f));
+ }
+
+ @Test
+ public void testGameDefaultFrameRate_FlagOff() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_GAME_DEFAULT_FRAME_RATE);
+ mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_GAME_MODE);
+
+ GameManagerService gameManagerService = Mockito.spy(
+ new GameManagerService(mMockContext, mTestLooper.getLooper(),
+ InstrumentationRegistry.getContext().getFilesDir(),
+ new Injector(){
+ @Override
+ public GameManagerServiceSystemPropertiesWrapper
+ createSystemPropertiesWrapper() {
+ return mSysPropsMock;
+ }
+ }));
+
+ // Set up a game in the foreground.
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+
+ // Toggle game default frame rate on.
+ when(mSysPropsMock.getInt(
+ ArgumentMatchers.eq(PROPERTY_RO_SURFACEFLINGER_GAME_DEFAULT_FRAME_RATE),
+ anyInt())).thenReturn(60);
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(true);
+
+ gameManagerService.toggleGameDefaultFrameRate(true);
+
+ // Verify that:
+ // 1) System property is never set
+ // 2) setGameDefaultFrameRateOverride() should never be called if the flag is disabled.
+ Mockito.verify(mSysPropsMock, never()).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ anyString());
+ Mockito.verify(gameManagerService, never())
+ .setGameDefaultFrameRateOverride(anyInt(), anyFloat());
+
+ // Toggle game default frame rate off.
+ String anotherGamePkg = "another.game";
+ String[] packages2 = {anotherGamePkg};
+ mockAppCategory(anotherGamePkg, ApplicationInfo.CATEGORY_GAME);
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ when(mSysPropsMock.getBoolean(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ ArgumentMatchers.eq(true))).thenReturn(false);
+
+ gameManagerService.toggleGameDefaultFrameRate(false);
+ // Verify that:
+ // 1) System property is never set
+ // 2) setGameDefaultFrameRateOverride() should never be called if the flag is disabled.
+ Mockito.verify(mSysPropsMock, never()).set(
+ ArgumentMatchers.eq(PROPERTY_PERSISTENT_GFX_GAME_DEFAULT_FRAME_RATE_ENABLED),
+ anyString());
+ Mockito.verify(gameManagerService, never())
+ .setGameDefaultFrameRateOverride(anyInt(), anyFloat());
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
index 23886a17c890..00fe3d92413c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
@@ -25,6 +25,7 @@ import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BACKGROUND
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -167,8 +168,12 @@ public class BackgroundJobsControllerTest {
}
private void setStoppedState(int uid, String pkgName, boolean stopped) {
- doReturn(stopped).when(mPackageManagerInternal).isPackageStopped(pkgName, uid);
- sendPackageStoppedBroadcast(uid, pkgName, stopped);
+ try {
+ doReturn(stopped).when(mPackageManagerInternal).isPackageStopped(pkgName, uid);
+ sendPackageStoppedBroadcast(uid, pkgName, stopped);
+ } catch (PackageManager.NameNotFoundException e) {
+ fail("Unable to set stopped state for unknown package: " + pkgName);
+ }
}
private void sendPackageStoppedBroadcast(int uid, String pkgName, boolean stopped) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index de8b3080907c..c2b52b4ee9c8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -45,14 +45,15 @@ import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -67,6 +68,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
@SmallTest
@Presubmit
@@ -106,6 +108,18 @@ public class ApexManagerTest {
public boolean hasFeature(String feature) {
return true;
}
+
+ @androidx.annotation.NonNull
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return new ArraySet<>();
+ }
+
+ @androidx.annotation.NonNull
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return new ArraySet<>();
+ }
});
mMockSystem.system().stageNominalSystemState();
@@ -385,7 +399,7 @@ public class ApexManagerTest {
findFactory(results, "test.apex.rebootless").apexInfo);
assertThat(factoryPkg.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath);
assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
- assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
+ assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue();
}
@Test
@@ -416,7 +430,7 @@ public class ApexManagerTest {
findFactory(results, "test.apex.rebootless").apexInfo);
assertThat(factoryPkg.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath);
assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
- assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
+ assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue();
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 28bd98781ced..7b29e2a4159d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -56,8 +56,10 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.spy
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder
import com.android.internal.R
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.internal.pm.pkg.parsing.ParsingPackage
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.LocalManagerRegistry
import com.android.server.LocalServices
import com.android.server.LockGuard
@@ -68,10 +70,8 @@ import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.pm.dex.DexManager
import com.android.server.pm.dex.DynamicCodeLogger
import com.android.server.pm.parsing.PackageParser2
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
@@ -81,14 +81,6 @@ import com.android.server.testutils.mock
import com.android.server.testutils.nullable
import com.android.server.testutils.whenever
import com.android.server.utils.WatchedArrayMap
-import libcore.util.HexEncoding
-import org.junit.Assert
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-import org.mockito.AdditionalMatchers.or
-import org.mockito.Mockito
-import org.mockito.quality.Strictness
import java.io.File
import java.io.IOException
import java.nio.file.Files
@@ -97,6 +89,14 @@ import java.security.cert.CertificateException
import java.util.Arrays
import java.util.Random
import java.util.concurrent.FutureTask
+import libcore.util.HexEncoding
+import org.junit.Assert
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import org.mockito.AdditionalMatchers.or
+import org.mockito.Mockito
+import org.mockito.quality.Strictness
/**
* A utility for mocking behavior of the system and dependencies when testing PackageManagerService
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
index 2332988cc832..e5ecdc478df7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
@@ -62,6 +62,7 @@ import android.os.ParcelableException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.text.TextUtils;
+import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -174,6 +175,7 @@ public class PackageArchiverTest {
mUserState = new PackageUserStateImpl().setInstalled(true);
mPackageSetting.setUserState(mUserId, mUserState);
when(mPackageState.getUserStateOrDefault(eq(mUserId))).thenReturn(mUserState);
+ when(mPackageState.getUserStates()).thenReturn(new SparseArray<>());
when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
when(mContext.getSystemService(AppOpsManager.class)).thenReturn(
@@ -343,7 +345,7 @@ public class PackageArchiverTest {
@Test
public void archiveApp_appOptedOutOfArchiving() {
- when(mAppOpsManager.checkOp(
+ when(mAppOpsManager.checkOpNoThrow(
eq(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED),
anyInt(), eq(PACKAGE))).thenReturn(MODE_IGNORED);
@@ -430,7 +432,7 @@ public class PackageArchiverTest {
@Test
public void isAppArchivable_appOptedOutOfArchiving()
throws PackageManager.NameNotFoundException {
- when(mAppOpsManager.checkOp(
+ when(mAppOpsManager.checkOpNoThrow(
eq(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED),
anyInt(), eq(PACKAGE))).thenReturn(MODE_IGNORED);
@@ -551,22 +553,12 @@ public class PackageArchiverTest {
when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn(
null);
- Exception e = assertThrows(
- ParcelableException.class,
- () -> mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT));
- assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
- assertThat(e.getCause()).hasMessageThat().isEqualTo(
- String.format("Package %s not found.", PACKAGE));
+ assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT)).isNull();
}
@Test
public void getArchivedAppIcon_notArchived() {
- Exception e = assertThrows(
- ParcelableException.class,
- () -> mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT));
- assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
- assertThat(e.getCause()).hasMessageThat().isEqualTo(
- String.format("Package %s is not currently archived.", PACKAGE));
+ assertThat(mArchiveManager.getArchivedAppIcon(PACKAGE, UserHandle.CURRENT)).isNull();
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
index a6ba5d4c3032..7b80aea80035 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageHelperTestBase.kt
@@ -36,6 +36,7 @@ import org.mockito.MockitoAnnotations
open class PackageHelperTestBase {
companion object {
+ const val PLATFORM_PACKAGE_NAME = "android"
const val TEST_PACKAGE_1 = "com.android.test.package1"
const val TEST_PACKAGE_2 = "com.android.test.package2"
const val DEVICE_OWNER_PACKAGE = "com.android.test.owner"
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index e685c3fa9fa4..944b1aae7bda 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -21,17 +21,17 @@ import android.content.pm.PackageManager
import android.content.pm.SharedLibraryInfo
import android.content.pm.VersionedPackage
import android.os.Build
-import android.os.storage.StorageManager
import android.os.UserHandle
+import android.os.storage.StorageManager
import android.util.ArrayMap
import android.util.PackageUtils
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.server.SystemConfig.SharedLibraryEntry
import com.android.server.compat.PlatformCompat
import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.testutils.any
import com.android.server.testutils.eq
import com.android.server.testutils.mock
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index 147303363200..7444403f88c8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -19,6 +19,7 @@ package com.android.server.pm
import android.app.AppOpsManager
import android.content.Intent
import android.content.pm.SuspendDialogInfo
+import android.content.pm.UserPackage
import android.os.Binder
import android.os.PersistableBundle
import com.android.server.testutils.any
@@ -41,12 +42,18 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
.thenReturn(AppOpsManager.MODE_DEFAULT)
}
+ companion object {
+ val doUserPackage = UserPackage.of(TEST_USER_ID, DEVICE_OWNER_PACKAGE)
+ val platformUserPackage = UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME)
+ val testUserPackage1 = UserPackage.of(TEST_USER_ID, TEST_PACKAGE_1)
+ }
+
@Test
fun setPackagesSuspended() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -63,14 +70,14 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_emptyPackageName() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
null /* packageNames */, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isNull()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOfNulls(0), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isEmpty()
@@ -80,7 +87,8 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_callerIsNotAllowed() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID,
+ null /* launcherExtras */, null /* dialogInfo */,
+ testUserPackage1, TEST_USER_ID,
Binder.getCallingUid(), false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -91,7 +99,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_callerSuspendItself() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -102,7 +110,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_nonexistentPackage() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -115,7 +123,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
knownPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)!!
assertThat(failedNames.size).isEqualTo(knownPackages.size)
@@ -129,14 +137,14 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, false /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -184,7 +192,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_1)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -202,22 +210,22 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
+ targetPackages, { suspender -> suspender.packageName == DEVICE_OWNER_PACKAGE },
TEST_USER_ID)
testHandler.flush()
@@ -243,7 +251,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -258,7 +266,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun isPackageSuspended() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -273,13 +281,79 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+ }
+
+ @Test
+ fun getSuspendingPackagePrecedence() {
+ val launcherExtras = PersistableBundle()
+ launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
+ val targetPackages = arrayOf(TEST_PACKAGE_2)
+ // Suspend.
+ var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
+ false /* quarantined */)
+ assertThat(failedNames).isEmpty()
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+
+ // Suspend by system.
+ failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ null /* dialogInfo */, platformUserPackage, TEST_USER_ID, deviceOwnerUid,
+ false /* quarantined */)
+ assertThat(failedNames).isEmpty()
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
+
+ // QAS by package1.
+ failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+ targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
+ null /* dialogInfo */, testUserPackage1, TEST_USER_ID, deviceOwnerUid,
+ true /* quarantined */)
+ assertThat(failedNames).isEmpty()
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(testUserPackage1)
+
+ // Un-QAS by package1.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspendingPackage -> suspendingPackage == testUserPackage1 },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
+
+ // Un-suspend by system.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspender -> suspender.packageName == PLATFORM_PACKAGE_NAME },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+
+ // Unsuspend.
+ suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+ targetPackages, { suspendingPackage -> suspendingPackage == doUserPackage },
+ TEST_USER_ID)
+ testHandler.flush()
+
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
}
@Test
@@ -288,13 +362,13 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
.setTitle(TEST_PACKAGE_1).build()
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+ null /* launcherExtras */, dialogInfo, doUserPackage, TEST_USER_ID,
deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
- TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
+ TEST_PACKAGE_1, doUserPackage, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
}
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 07197b1ab9df..05e0e8f4a4f7 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -3,6 +3,20 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
+filegroup {
+ name: "power_stats_ravenwood_tests",
+ srcs: [
+ "src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java",
+ "src/com/android/server/power/stats/AggregatedPowerStatsTest.java",
+ "src/com/android/server/power/stats/MultiStateStatsTest.java",
+ "src/com/android/server/power/stats/PowerStatsAggregatorTest.java",
+ "src/com/android/server/power/stats/PowerStatsCollectorTest.java",
+ "src/com/android/server/power/stats/PowerStatsSchedulerTest.java",
+ "src/com/android/server/power/stats/PowerStatsStoreTest.java",
+ "src/com/android/server/power/stats/PowerStatsUidResolverTest.java",
+ ],
+}
+
android_test {
name: "PowerStatsTests",
@@ -12,8 +26,7 @@ android_test {
],
exclude_srcs: [
- "src/com/android/server/power/stats/MultiStateStatsTest.java",
- "src/com/android/server/power/stats/PowerStatsStoreTest.java",
+ ":power_stats_ravenwood_tests",
],
static_libs: [
@@ -65,10 +78,12 @@ android_ravenwood_test {
"modules-utils-binary-xml",
"androidx.annotation_annotation",
"androidx.test.rules",
+ "truth",
+ "mockito_ravenwood",
],
srcs: [
- "src/com/android/server/power/stats/MultiStateStatsTest.java",
- "src/com/android/server/power/stats/PowerStatsStoreTest.java",
+ ":power_stats_ravenwood_tests",
+ "src/com/android/server/power/stats/MockClock.java",
],
auto_gen_config: true,
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatePowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java
index 6d61dc8d31fa..af83be04db7d 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatePowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java
@@ -35,7 +35,7 @@ import java.util.Objects;
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class AggregatePowerStatsProcessorTest {
+public class AggregatedPowerStatsProcessorTest {
@Test
public void createPowerEstimationPlan_allDeviceStatesPresentInUidStates() {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
index e8f46b30fb8c..1b045c532759 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
@@ -22,12 +22,10 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import android.os.BatteryConsumer;
-import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,11 +36,6 @@ import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MultiStateStatsTest {
-
- @Rule
- public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
- .build();
-
public static final int DIMENSION_COUNT = 2;
@Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
index 67049871f396..2456636970fa 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.mock;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.PersistableBundle;
-import android.text.format.DateFormat;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
@@ -39,7 +38,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.text.ParseException;
-import java.util.Calendar;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.List;
import java.util.TimeZone;
@@ -60,7 +60,7 @@ public class PowerStatsAggregatorTest {
public void setup() throws ParseException {
mHistory = new BatteryStatsHistory(32, 1024,
mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,
- mMonotonicClock);
+ mMonotonicClock, mock(BatteryStatsHistory.TraceDelegate.class));
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
config.trackPowerComponent(TEST_POWER_COMPONENT)
@@ -179,9 +179,9 @@ public class PowerStatsAggregatorTest {
@NonNull
private static CharSequence formatDateTime(long timeInMillis) {
- Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
- cal.setTimeInMillis(timeInMillis);
- return DateFormat.format("yyyy-MM-dd hh:mm:ss", cal);
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
+ format.getCalendar().setTimeZone(TimeZone.getTimeZone("GMT"));
+ return format.format(new Date(timeInMillis));
}
@Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
index 330f698277f8..17a7d3ecf9d3 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
@@ -22,6 +22,7 @@ import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PersistableBundle;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +30,18 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.PowerStats;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PowerStatsCollectorTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
private final MockClock mMockClock = new MockClock();
private final HandlerThread mHandlerThread = new HandlerThread("test");
private Handler mHandler;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java
index 7257a94cbb9a..beec66156fe4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsSchedulerTest.java
@@ -24,26 +24,26 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import android.content.Context;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
+import android.platform.test.ravenwood.RavenwoodRule;
-import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.MonotonicClock;
-import com.android.internal.os.PowerProfile;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
import java.time.Duration;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@@ -51,39 +51,46 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class PowerStatsSchedulerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
private PowerStatsStore mPowerStatsStore;
private Handler mHandler;
private MockClock mClock = new MockClock();
private MonotonicClock mMonotonicClock = new MonotonicClock(0, mClock);
- private MockBatteryStatsImpl mBatteryStats;
private PowerStatsScheduler mPowerStatsScheduler;
- private PowerProfile mPowerProfile;
private PowerStatsAggregator mPowerStatsAggregator;
private AggregatedPowerStatsConfig mAggregatedPowerStatsConfig;
+ private List<Long> mScheduledAlarms = new ArrayList<>();
+ private boolean mPowerStatsCollectionOccurred;
+
+ private static final int START_REALTIME = 7654321;
@Before
@SuppressWarnings("GuardedBy")
- public void setup() {
- final Context context = InstrumentationRegistry.getContext();
-
+ public void setup() throws IOException {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mClock.currentTime = Instant.parse("2023-01-02T03:04:05.00Z").toEpochMilli();
- mClock.realtime = 7654321;
+ mClock.realtime = START_REALTIME;
HandlerThread bgThread = new HandlerThread("bg thread");
bgThread.start();
- File systemDir = context.getCacheDir();
mHandler = new Handler(bgThread.getLooper());
mAggregatedPowerStatsConfig = new AggregatedPowerStatsConfig();
- mPowerStatsStore = new PowerStatsStore(systemDir, mHandler, mAggregatedPowerStatsConfig);
- mPowerProfile = mock(PowerProfile.class);
- when(mPowerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT)).thenReturn(1000000.0);
- mBatteryStats = new MockBatteryStatsImpl(mClock).setPowerProfile(mPowerProfile);
+ mPowerStatsStore = new PowerStatsStore(
+ Files.createTempDirectory("PowerStatsSchedulerTest").toFile(),
+ mHandler, mAggregatedPowerStatsConfig);
mPowerStatsAggregator = mock(PowerStatsAggregator.class);
- mPowerStatsScheduler = new PowerStatsScheduler(context, mPowerStatsAggregator,
- TimeUnit.MINUTES.toMillis(30), TimeUnit.HOURS.toMillis(1), mPowerStatsStore, mClock,
- mMonotonicClock, mHandler, mBatteryStats);
+ mPowerStatsScheduler = new PowerStatsScheduler(
+ () -> mPowerStatsCollectionOccurred = true,
+ mPowerStatsAggregator, TimeUnit.MINUTES.toMillis(30), TimeUnit.HOURS.toMillis(1),
+ mPowerStatsStore,
+ ((triggerAtMillis, tag, onAlarmListener, handler) ->
+ mScheduledAlarms.add(triggerAtMillis)),
+ mClock, mMonotonicClock, () -> 12345L, mHandler);
}
@Test
@@ -113,7 +120,7 @@ public class PowerStatsSchedulerTest {
long endTimeWallClock =
mClock.currentTime - (mMonotonicClock.monotonicTime() - endTime);
- assertThat(startTime).isEqualTo(7654321 + 123);
+ assertThat(startTime).isEqualTo(START_REALTIME + 123);
assertThat(endTime - startTime).isAtLeast(TimeUnit.MINUTES.toMillis(30));
assertThat(Instant.ofEpochMilli(endTimeWallClock))
.isEqualTo(Instant.parse("2023-01-02T04:00:00Z"));
@@ -142,11 +149,15 @@ public class PowerStatsSchedulerTest {
}).when(mPowerStatsAggregator).aggregatePowerStats(anyLong(), anyLong(),
any(Consumer.class));
- mPowerStatsScheduler.schedulePowerStatsAggregation();
+ mPowerStatsScheduler.start(/*enabled*/ true);
ConditionVariable done = new ConditionVariable();
mHandler.post(done::open);
done.block();
+ assertThat(mPowerStatsCollectionOccurred).isTrue();
+ assertThat(mScheduledAlarms).containsExactly(
+ START_REALTIME + TimeUnit.MINUTES.toMillis(90) + TimeUnit.HOURS.toMillis(1));
+
verify(mPowerStatsAggregator, times(2))
.aggregatePowerStats(anyLong(), anyLong(), any(Consumer.class));
@@ -155,7 +166,7 @@ public class PowerStatsSchedulerTest {
// Skip the first entry, which was placed in the store at the beginning of this test
PowerStatsSpan.TimeFrame timeFrame1 = contents.get(1).getTimeFrames().get(0);
PowerStatsSpan.TimeFrame timeFrame2 = contents.get(2).getTimeFrames().get(0);
- assertThat(timeFrame1.startMonotonicTime).isEqualTo(7654321 + 123);
+ assertThat(timeFrame1.startMonotonicTime).isEqualTo(START_REALTIME + 123);
assertThat(timeFrame2.startMonotonicTime)
.isEqualTo(timeFrame1.startMonotonicTime + timeFrame1.duration);
assertThat(Instant.ofEpochMilli(timeFrame2.startTime))
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index a78f2dcf2ab2..3b5cae328b3c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -23,6 +23,8 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
@@ -41,6 +43,7 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -108,6 +111,7 @@ public class AuthServiceTest {
@Mock
IFaceService mFaceService;
@Mock
+
AppOpsManager mAppOpsManager;
@Mock
private VirtualDeviceManagerInternal mVdmInternal;
@@ -404,6 +408,23 @@ public class AuthServiceTest {
eq(TEST_OP_PACKAGE_NAME));
}
+ @Test
+ public void testRegisterAuthenticationStateListener_callsFingerprintService()
+ throws Exception {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
+
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final AuthenticationStateListener listener = mock(AuthenticationStateListener.class);
+
+ mAuthService.mImpl.registerAuthenticationStateListener(listener);
+
+ waitForIdle();
+ verify(mFingerprintService).registerAuthenticationStateListener(
+ eq(listener));
+ }
@Test
public void testRegisterKeyguardCallback_callsBiometricServiceRegisterKeyguardCallback()
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index 5012335b533f..94cb860ae710 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -23,10 +25,11 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import androidx.test.filters.SmallTest;
@@ -40,6 +43,7 @@ import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
+@RequiresFlagsDisabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
@Presubmit
@SmallTest
public class SensorOverlaysTest {
@@ -97,7 +101,7 @@ public class SensorOverlaysTest {
private void testShow(IUdfpsOverlayController udfps, ISidefpsController sidefps)
throws Exception {
final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps);
- final int reason = BiometricOverlayConstants.REASON_UNKNOWN;
+ final int reason = BiometricRequestConstants.REASON_UNKNOWN;
sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
if (udfps != null) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 79a528c59f49..c24227fcd1f7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -18,6 +18,8 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -56,6 +58,7 @@ import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
@@ -68,6 +71,7 @@ import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -91,6 +95,8 @@ import java.util.function.Consumer;
@SmallTest
public class FingerprintAuthenticationClientTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final int SENSOR_ID = 4;
private static final int USER_ID = 8;
private static final long OP_ID = 7;
@@ -128,6 +134,8 @@ public class FingerprintAuthenticationClientTest {
@Mock
private ISidefpsController mSideFpsController;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private FingerprintSensorPropertiesInternal mSensorProps;
@Mock
private ClientMonitorCallback mCallback;
@@ -384,6 +392,7 @@ public class FingerprintAuthenticationClientTest {
private void showHideOverlay(Consumer<FingerprintAuthenticationClient> block)
throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
@@ -398,6 +407,49 @@ public class FingerprintAuthenticationClientTest {
}
@Test
+ public void showHideOverlay_cancel_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.cancel());
+ }
+
+ @Test
+ public void showHideOverlay_stop_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.stopHalOperation());
+ }
+
+ @Test
+ public void showHideOverlay_error_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onError(0, 0));
+ verify(mCallback).onClientFinished(any(), eq(false));
+ }
+
+ @Test
+ public void showHideOverlay_lockout_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onLockoutTimed(5000));
+ }
+
+ @Test
+ public void showHideOverlay_lockoutPerm_sidefpsControllerRemovalRefactor()
+ throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onLockoutPermanent());
+ }
+
+ private void showHideOverlay_sidefpsControllerRemovalRefactor(
+ Consumer<FingerprintAuthenticationClient> block) throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ final FingerprintAuthenticationClient client = createClient();
+
+ client.start(mCallback);
+
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
+ verify(mAuthenticationStateListeners).onAuthenticationStarted(anyInt());
+
+ block.accept(client);
+
+ verify(mUdfpsOverlayController).hideUdfpsOverlay(anyInt());
+ verify(mAuthenticationStateListeners).onAuthenticationStopped();
+ }
+
+ @Test
public void cancelsAuthWhenNotInForeground() throws Exception {
final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo();
topTask.topActivity = new ComponentName("other", "thing");
@@ -502,7 +554,8 @@ public class FingerprintAuthenticationClientTest {
mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
null /* taskStackListener */,
- mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication,
+ mUdfpsOverlayController, mSideFpsController, mAuthenticationStateListeners,
+ allowBackgroundAuthentication,
mSensorProps,
new Handler(mLooper.getLooper()), 0 /* biometricStrength */, mClock,
lockoutTracker) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index c7eb1db3e74b..e7d4a2e463f7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -38,6 +40,7 @@ import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
@@ -48,6 +51,7 @@ import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -68,6 +72,8 @@ import java.util.function.Consumer;
@SmallTest
public class FingerprintEnrollClientTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 8;
private static final long REQUEST_ID = 9;
@@ -98,6 +104,8 @@ public class FingerprintEnrollClientTest {
@Mock
private ISidefpsController mSideFpsController;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private FingerprintSensorPropertiesInternal mSensorProps;
@Mock
private ClientMonitorCallback mCallback;
@@ -271,6 +279,7 @@ public class FingerprintEnrollClientTest {
private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
final FingerprintEnrollClient client = createClient();
client.start(mCallback);
@@ -284,6 +293,44 @@ public class FingerprintEnrollClientTest {
verify(mSideFpsController).hide(anyInt());
}
+ @Test
+ public void showHideOverlay_cancel_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.cancel());
+ }
+
+ @Test
+ public void showHideOverlay_stop_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.stopHalOperation());
+ }
+
+ @Test
+ public void showHideOverlay_error_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onError(0, 0));
+ verify(mCallback).onClientFinished(any(), eq(false));
+ }
+
+ @Test
+ public void showHideOverlay_result_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(
+ c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0));
+ }
+
+ private void showHideOverlay_sidefpsControllerRemovalRefactor(
+ Consumer<FingerprintEnrollClient> block) throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ final FingerprintEnrollClient client = createClient();
+
+ client.start(mCallback);
+
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
+ verify(mAuthenticationStateListeners).onAuthenticationStarted(anyInt());
+
+ block.accept(client);
+
+ verify(mUdfpsOverlayController).hideUdfpsOverlay(anyInt());
+ verify(mAuthenticationStateListeners).onAuthenticationStopped();
+ }
+
private FingerprintEnrollClient createClient() throws RemoteException {
return createClient(500);
}
@@ -296,6 +343,7 @@ public class FingerprintEnrollClientTest {
mClientMonitorCallbackConverter, 0 /* userId */,
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
- mSideFpsController, 6 /* maxTemplatesPerUser */, FingerprintManager.ENROLL_ENROLL);
+ mSideFpsController, mAuthenticationStateListeners, 6 /* maxTemplatesPerUser */,
+ FingerprintManager.ENROLL_ENROLL);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 8f6efffcbff8..4cfb83fa1c69 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -43,6 +43,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -74,6 +75,8 @@ public class FingerprintProviderTest {
@Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -110,8 +113,9 @@ public class FingerprintProviderTest {
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFingerprintProvider = new FingerprintProvider(mContext,
- mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher, mBiometricContext, mDaemon);
+ mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext,
+ mDaemon);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
index b32b89aaefb0..0d3f1921c947 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
@@ -40,6 +40,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -70,6 +71,8 @@ public class Fingerprint21Test {
@Mock
private BiometricScheduler mScheduler;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -102,9 +105,10 @@ public class Fingerprint21Test {
componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN,
resetLockoutRequiresHardwareAuthToken);
- mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback, sensorProps,
- mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher,
- mHalResultController, mBiometricContext);
+ mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback,
+ mAuthenticationStateListeners, sensorProps, mScheduler,
+ new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController,
+ mBiometricContext);
}
@Test
@@ -126,13 +130,14 @@ public class Fingerprint21Test {
TestableFingerprint21(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, biometricContext);
+ super(context, biometricStateCallback, authenticationStateListeners, sensorProps,
+ scheduler, handler, lockoutResetDispatcher, controller, biometricContext);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index 943a9c4759c4..1dd64ffa5dde 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -18,7 +18,6 @@ package com.android.server.devicepolicy;
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -222,21 +221,21 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isSuspendingAnyPackages(
- PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
+ USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
verify(getServices().packageManagerInternal, never())
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
sendBroadcastWithUser(dpms, Intent.ACTION_USER_STARTED, USER_SYSTEM);
// Verify that actual package suspension state is not modified after user start
verify(getServices().packageManagerInternal, never())
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt());
+ any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
@@ -255,14 +254,14 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isSuspendingAnyPackages(
- PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
+ USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
// Verify that apps get unsuspended.
verify(getServices().packageManagerInternal)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f4dac2c10d0f..24704034ae0c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -63,7 +63,6 @@ import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static com.google.common.truth.Truth.assertThat;
@@ -5080,7 +5079,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().iwindowManager).refreshScreenCaptureDisabled();
// Unsuspend personal apps
verify(getServices().packageManagerInternal)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(UserHandle.USER_SYSTEM);
verify(getServices().subscriptionManager).setSubscriptionUserHandle(0, null);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "false", false);
@@ -7535,7 +7534,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.cancel(eq(SystemMessageProto.SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
// Verify that the apps are NOT unsuspeded.
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt());
+ any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
// Verify that DPC is invoked to check policy compliance.
verify(mContext.spiedContext).startActivityAsUser(
MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
index fe37f4241d8e..b3d25f2eef25 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
@@ -47,6 +47,10 @@ import java.util.Map;
@Presubmit
@RunWith(AndroidJUnit4.class)
public final class OverrideRequestControllerTest {
+
+ private static final DeviceState TEST_DEVICE_STATE_ZERO = new DeviceState(0, "TEST_STATE", 0);
+ private static final DeviceState TEST_DEVICE_STATE_ONE = new DeviceState(1, "TEST_STATE", 0);
+
private TestStatusChangeListener mStatusListener;
private OverrideRequestController mController;
@@ -59,7 +63,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest() {
OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(request));
mController.addRequest(request);
@@ -69,14 +73,14 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest_cancelExistingRequestThroughNewRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
mController.addRequest(secondRequest);
@@ -87,7 +91,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addRequest_cancelActiveRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
@@ -101,7 +105,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest() {
OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(request));
mController.addBaseStateRequest(request);
@@ -111,14 +115,14 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest_cancelExistingBaseStateRequestThroughNewRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addBaseStateRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
mController.addBaseStateRequest(secondRequest);
@@ -129,7 +133,7 @@ public final class OverrideRequestControllerTest {
@Test
public void addBaseStateRequest_cancelActiveBaseStateRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addBaseStateRequest(firstRequest);
@@ -143,13 +147,13 @@ public final class OverrideRequestControllerTest {
@Test
public void handleBaseStateChanged() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */,
+ TEST_DEVICE_STATE_ZERO,
DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES /* flags */,
OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 0 /* requestedState */,
+ TEST_DEVICE_STATE_ZERO,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -169,11 +173,11 @@ public final class OverrideRequestControllerTest {
@Test
public void handleProcessDied() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */,
+ TEST_DEVICE_STATE_ONE,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -192,11 +196,11 @@ public final class OverrideRequestControllerTest {
mController.setStickyRequestsAllowed(true);
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
@@ -215,11 +219,11 @@ public final class OverrideRequestControllerTest {
@Test
public void handleNewSupportedStates() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */,
+ TEST_DEVICE_STATE_ONE,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -242,7 +246,7 @@ public final class OverrideRequestControllerTest {
@Test
public void cancelOverrideRequestsTest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index a2a8424881d4..0973d46283ed 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -23,6 +23,7 @@ import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
import static com.android.server.hdmi.Constants.ADDR_RECORDER_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static com.google.common.truth.Truth.assertThat;
@@ -1712,13 +1713,14 @@ public class HdmiCecLocalDeviceTvTest {
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
-
mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
+ assertThat(mHdmiControlService.getLocalActiveSource()).isEqualTo(
+ new ActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS));
mNativeWrapper.clearResultMessages();
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
@@ -1728,8 +1730,64 @@ public class HdmiCecLocalDeviceTvTest {
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(activeSourceFromTv);
+ assertThat(mHdmiControlService.getLocalActiveSource()).isEqualTo(
+ new ActiveSource(mTvLogicalAddress, mTvPhysicalAddress));
+ }
+
+ @Test
+ public void requestActiveSourceActionComplete_validLocalActiveSource_doNotSendActiveSource() {
+ HdmiCecMessage requestActiveSource =
+ HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
+ HdmiCecMessage activeSourceFromTv =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
+ mHdmiControlService.setActiveSource(mTvLogicalAddress, mTvPhysicalAddress,
+ "HdmiCecLocalDeviceTvTest");
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
+ }
+
+ @Test
+ public void onAddressAllocated_startRequestActiveSourceAction_cancelOnDeviceSelect() {
+ HdmiCecMessage requestActiveSource =
+ HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
+ HdmiCecMessage activeSourceFromTv =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ HdmiDeviceInfo playbackDevice = HdmiDeviceInfo.cecDeviceBuilder()
+ .setLogicalAddress(ADDR_PLAYBACK_1)
+ .setPhysicalAddress(0x1000)
+ .setPortId(PORT_1)
+ .setDeviceType(HdmiDeviceInfo.DEVICE_PLAYBACK)
+ .setVendorId(0x1234)
+ .setDisplayName("Playback 1")
+ .setDevicePowerStatus(HdmiControlManager.POWER_STATUS_ON)
+ .setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B)
+ .build();
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(playbackDevice);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
+ mNativeWrapper.clearResultMessages();
+ mHdmiCecLocalDeviceTv.deviceSelect(playbackDevice.getId(), null);
+ mTestLooper.dispatchAll();
+
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
+ // RequestActiveSourceAction should be cancelled and TV will not broadcast <Active Source>.
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
}
+
@Test
public void newDeviceConnectedIfOnlyOneGiveOsdNameSent() {
mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
@@ -1737,7 +1795,7 @@ public class HdmiCecLocalDeviceTvTest {
.isEmpty();
HdmiCecMessage reportPhysicalAddress =
HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
HdmiCecMessage giveOsdName = HdmiCecMessageBuilder.buildGiveOsdNameCommand(
ADDR_TV, ADDR_PLAYBACK_2);
mNativeWrapper.onCecMessage(reportPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
index fb7857494515..0d25faf2bcf1 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
@@ -60,6 +60,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.inputmethod.StartInputFlags;
+import com.google.common.truth.Truth;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -1336,6 +1338,54 @@ public class InputMethodUtilsTest {
}
}
+ private static void verifySplitEnabledImeStr(@NonNull String enabledImeStr,
+ @NonNull String... expected) {
+ final ArrayList<String> actual = new ArrayList<>();
+ InputMethodUtils.splitEnabledImeStr(enabledImeStr, actual::add);
+ if (expected.length == 0) {
+ Truth.assertThat(actual).isEmpty();
+ } else {
+ Truth.assertThat(actual).containsExactlyElementsIn(expected);
+ }
+ }
+
+ @Test
+ public void testSplitEnabledImeStr() {
+ verifySplitEnabledImeStr("");
+ verifySplitEnabledImeStr("com.android/.ime1", "com.android/.ime1");
+ verifySplitEnabledImeStr("com.android/.ime1;1;2;3", "com.android/.ime1");
+ verifySplitEnabledImeStr("com.android/.ime1;1;2;3:com.android/.ime2",
+ "com.android/.ime1", "com.android/.ime2");
+ verifySplitEnabledImeStr("com.android/.ime1:com.android/.ime2",
+ "com.android/.ime1", "com.android/.ime2");
+ verifySplitEnabledImeStr("com.android/.ime1:com.android/.ime2:com.android/.ime3",
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3");
+ verifySplitEnabledImeStr("com.android/.ime1;1:com.android/.ime2;1:com.android/.ime3;1",
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3");
+ }
+
+ @Test
+ public void testConcatEnabledImeIds() {
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds("")).isEmpty();
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds("", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime2"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2:com.android/.ime3");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1:com.android/.ime2", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1:com.android/.ime2", "com.android/.ime3"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2:com.android/.ime3");
+ }
+
@Test
public void updateEnabledImeStringTest() {
// No change cases
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 18961c0feef9..ee076c6bcf4b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -140,9 +140,9 @@ public class LockSettingsServiceTestable extends LockSettingsService {
}
@Override
- public ManagedProfilePasswordCache getManagedProfilePasswordCache(
+ public UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(
java.security.KeyStore ks) {
- return mock(ManagedProfilePasswordCache.class);
+ return mock(UnifiedProfilePasswordCache.class);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index dd687fd4286c..86a1358f371c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -27,9 +27,9 @@ import static org.mockito.Mockito.when;
import android.os.Build;
import android.platform.test.annotations.Presubmit;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.PackageState;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 8464969cd0f3..ee93bc1e3562 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -53,10 +53,10 @@ import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.After;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 0f87202f8939..587f5fa9c623 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -29,9 +29,9 @@ import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import dalvik.system.DelegateLastClassLoader;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index ee23a00f27d7..9b4ca2a86f2c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -21,17 +21,17 @@ import android.os.Environment
import android.os.SystemProperties.PROP_VALUE_MAX
import android.platform.test.annotations.Postsubmit
import com.android.internal.R
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.PackageManagerService
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.File
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Assert.fail
import org.junit.Test
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
-import java.io.ByteArrayInputStream
-import java.io.File
@Postsubmit
class AndroidPackageParsingValidationTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
index 2332817911f7..c44f583a93ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
@@ -17,6 +17,7 @@
package com.android.server.pm.parsing
import android.content.pm.ApplicationInfo
+import android.util.ArraySet
import java.io.File
class TestPackageParser2(var cacheDir: File? = null) : PackageParser2(
@@ -33,4 +34,7 @@ class TestPackageParser2(var cacheDir: File? = null) : PackageParser2(
// behavior.
return false
}
+
+ override fun getHiddenApiWhitelistedApps() = ArraySet<String>()
+ override fun getInstallConstraintsAllowlist() = ArraySet<String>()
})
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index 5ba4851270fd..759b204516c6 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -32,8 +32,9 @@ import android.content.rollback.PackageRollbackInfo;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.PackageList;
-import com.android.server.pm.parsing.pkg.PackageImpl;
+
import com.google.common.collect.Range;
import org.junit.Before;
@@ -415,7 +416,7 @@ public class RollbackUnitTest {
private void addPkgWithMinExtVersions(String pkg, int[][] minExtVersions) {
mPackages.add(pkg);
- PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false);
+ PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false, null);
pkgImpl.setMinExtensionVersions(sparseArrayFrom(minExtVersions));
when(mMockPmi.getPackage(pkg)).thenReturn(pkgImpl);
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 6335b3bfade2..4e1c72af2727 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -46,6 +46,7 @@ android_test {
"testng",
"flag-junit",
"notification_flags_lib",
+ "platform-test-rules",
],
libs: [
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 8bb11a45181e..776189eeb7c3 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -209,12 +209,17 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.permission.PermissionManager;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.rule.DeniedDevices;
+import android.platform.test.rule.DeviceProduct;
+import android.platform.test.rule.LimitDevicesRule;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.ConversationChannelWrapper;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
@@ -280,6 +285,7 @@ import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -312,6 +318,7 @@ import java.util.function.Consumer;
@RunWith(AndroidTestingRunner.class)
@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
@RunWithLooper
+@DeniedDevices(denied = {DeviceProduct.CF_AUTO})
public class NotificationManagerServiceTest extends UiServiceTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package";
@@ -330,6 +337,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private final int mUid = Binder.getCallingUid();
private final @UserIdInt int mUserId = UserHandle.getUserId(mUid);
+ @ClassRule
+ public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule();
+
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -626,6 +636,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
private void initNMS() throws Exception {
+ initNMS(SystemService.PHASE_BOOT_COMPLETED);
+ }
+
+ private void initNMS(int upToBootPhase) throws Exception {
mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
mNotificationInstanceIdSequence);
@@ -653,13 +667,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
mPowerManager, mPostNotificationTrackerFactory);
+
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
- mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
+
+ if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
+ }
+
Mockito.reset(mHistoryManager);
verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
- mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
- verify(mHistoryManager).onBootPhaseAppsCanStart();
+
+ if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
+ verify(mHistoryManager).onBootPhaseAppsCanStart();
+ }
// TODO b/291907312: remove feature flag
if (Flags.refactorAttentionHelper()) {
@@ -905,7 +927,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel.setAllowBubbles(channelEnabled);
}
- private void setUpPrefsForHistory(int uid, boolean globalEnabled) {
+ private void setUpPrefsForHistory(int uid, boolean globalEnabled) throws Exception {
+ initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+
// Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, uid);
@@ -971,6 +995,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
return new NotificationRecord(mContext, sbn, channel);
}
+ private NotificationRecord generateNotificationRecord(NotificationChannel channel,
+ long postTime) {
+ final StatusBarNotification sbn = generateSbn(PKG, mUid, postTime, 0);
+ return new NotificationRecord(mContext, sbn, channel);
+ }
+
private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) {
return generateNotificationRecord(channel, 1, userId);
}
@@ -8978,6 +9008,42 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception {
+ mService.setCallerIsNormalPackage();
+ mService.setZenHelper(mock(ZenModeHelper.class));
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
+ .setType(AutomaticZenRule.TYPE_MANAGED)
+ .setOwner(new ComponentName("pkg", "cls"))
+ .build();
+ when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true);
+
+ mBinderService.addAutomaticZenRule(rule, "pkg");
+ // No exception!
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception {
+ mService.setCallerIsNormalPackage();
+ mService.setZenHelper(mock(ZenModeHelper.class));
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
+ .setType(AutomaticZenRule.TYPE_MANAGED)
+ .setOwner(new ComponentName("pkg", "cls"))
+ .build();
+ when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mBinderService.addAutomaticZenRule(rule, "pkg"));
+ }
+
+ @Test
public void onZenModeChanged_sendsBroadcasts() throws Exception {
when(mAmi.getCurrentUserId()).thenReturn(100);
when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
@@ -10039,7 +10105,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testHandleOnPackageRemoved_ClearsHistory() throws RemoteException {
+ public void testHandleOnPackageRemoved_ClearsHistory() throws Exception {
// Enables Notification History setting
setUpPrefsForHistory(mUid, true /* =enabled */);
@@ -13158,6 +13224,34 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_succeeds() throws Exception {
+ initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+ // No exception!
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_tooLate_throws() throws Exception {
+ initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+
+ assertThrows(IllegalStateException.class, () ->
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_calledTwice_throws() throws Exception {
+ initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+ assertThrows(IllegalStateException.class, () ->
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
+ }
+
+ @Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
@@ -13312,6 +13406,175 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
}
+ @Test
+ public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne()
+ throws RemoteException {
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create recent notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis());
+ mService.addNotification(nr1);
+
+ // Create old notification.
+ final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr2);
+
+ // Cancel specific notifications via listener.
+ String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
+ mService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+
+ // Notifications should not be active anymore.
+ StatusBarNotification[] notifications = mBinderService.getActiveNotifications(PKG);
+ assertThat(notifications).isEmpty();
+ assertEquals(0, mService.getNotificationRecordCount());
+ // Ensure cancel event is logged.
+ verify(mAppOpsManager).noteOpNoThrow(
+ AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, PKG, null, null);
+ }
+
+ @Test
+ public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create old notifications.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr1);
+
+ final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr2);
+
+ // Cancel specific notifications via listener.
+ String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
+ mService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+
+ // Notifications should not be active anymore.
+ StatusBarNotification[] notifications = mBinderService.getActiveNotifications(PKG);
+ assertThat(notifications).isEmpty();
+ assertEquals(0, mService.getNotificationRecordCount());
+ // Ensure cancel event is not logged.
+ verify(mAppOpsManager, never()).noteOpNoThrow(
+ eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled()
+ throws RemoteException {
+ mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create recent notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis());
+ mService.addNotification(nr1);
+
+ // Create old notification.
+ final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr2);
+
+ // Cancel specific notifications via listener.
+ String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()};
+ mService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+
+ // Notifications should not be active anymore.
+ StatusBarNotification[] notifications = mBinderService.getActiveNotifications(PKG);
+ assertThat(notifications).isEmpty();
+ assertEquals(0, mService.getNotificationRecordCount());
+ // Ensure cancel event is not logged due to flag being disabled.
+ verify(mAppOpsManager, never()).noteOpNoThrow(
+ eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll()
+ throws RemoteException {
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create recent notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis());
+ mService.addNotification(nr1);
+
+ // Create old notification.
+ final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr2);
+
+ // Cancel all notifications via listener.
+ mService.getBinderService().cancelNotificationsFromListener(null, null);
+ waitForIdle();
+
+ // Notifications should not be active anymore.
+ StatusBarNotification[] notifications = mBinderService.getActiveNotifications(PKG);
+ assertThat(notifications).isEmpty();
+ assertEquals(0, mService.getNotificationRecordCount());
+ // Ensure cancel event is logged.
+ verify(mAppOpsManager).noteOpNoThrow(
+ AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, PKG, null, null);
+ }
+
+ @Test
+ public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create old notifications.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr1);
+
+ final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr2);
+
+ // Cancel all notifications via listener.
+ mService.getBinderService().cancelNotificationsFromListener(null, null);
+ waitForIdle();
+
+ // Notifications should not be active anymore.
+ StatusBarNotification[] notifications = mBinderService.getActiveNotifications(PKG);
+ assertThat(notifications).isEmpty();
+ assertEquals(0, mService.getNotificationRecordCount());
+ // Ensure cancel event is not logged.
+ verify(mAppOpsManager, never()).noteOpNoThrow(
+ eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled()
+ throws RemoteException {
+ mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create recent notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis());
+ mService.addNotification(nr1);
+
+ // Create old notification.
+ final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(nr2);
+
+ // Cancel all notifications via listener.
+ mService.getBinderService().cancelNotificationsFromListener(null, null);
+ waitForIdle();
+
+ // Notifications should not be active anymore.
+ StatusBarNotification[] notifications = mBinderService.getActiveNotifications(PKG);
+ assertThat(notifications).isEmpty();
+ assertEquals(0, mService.getNotificationRecordCount());
+ // Ensure cancel event is not logged due to flag being disabled.
+ verify(mAppOpsManager, never()).noteOpNoThrow(
+ eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
+ any(), any());
+ }
+
private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
throws RemoteException {
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, testName, mUid, 0,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 646ee3f6d206..1aea56cd8f9f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -80,6 +80,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.notNull;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -265,10 +266,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
.thenReturn(CUSTOM_PKG_UID);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
new String[] {pkg});
- ApplicationInfo mockAppInfo = mock(ApplicationInfo.class);
- when(mockAppInfo.loadLabel(any())).thenReturn(CUSTOM_APP_LABEL);
+
+ ApplicationInfo appInfoSpy = spy(new ApplicationInfo());
+ appInfoSpy.icon = ICON_RES_ID;
+ when(appInfoSpy.loadLabel(any())).thenReturn(CUSTOM_APP_LABEL);
when(mPackageManager.getApplicationInfo(eq(CUSTOM_PKG_NAME), anyInt()))
- .thenReturn(mockAppInfo);
+ .thenReturn(appInfoSpy);
mZenModeHelper.mPm = mPackageManager;
mZenModeEventLogger.reset();
@@ -3753,6 +3756,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
rule.zenPolicy = policy;
rule.pkg = ownerPkg;
rule.name = CUSTOM_APP_LABEL;
+ rule.iconResName = ICON_RES_NAME;
+ rule.triggerDescription = mContext.getString(R.string.zen_mode_implicit_trigger_description,
+ CUSTOM_APP_LABEL);
+ rule.type = AutomaticZenRule.TYPE_OTHER;
rule.enabled = true;
return rule;
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
new file mode 100644
index 000000000000..49efd1bdd92a
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.RemoteException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class VibratorControlServiceTest {
+
+ private VibratorControlService mVibratorControlService;
+ private final Object mLock = new Object();
+
+ @Before
+ public void setUp() throws Exception {
+ mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(), mLock);
+ }
+
+ @Test
+ public void testRegisterVibratorController() throws RemoteException {
+ FakeVibratorController fakeController = new FakeVibratorController();
+ mVibratorControlService.registerVibratorController(fakeController);
+
+ assertThat(fakeController.isLinkedToDeath).isTrue();
+ }
+
+ @Test
+ public void testUnregisterVibratorController_providingTheRegisteredController_performsRequest()
+ throws RemoteException {
+ FakeVibratorController fakeController = new FakeVibratorController();
+ mVibratorControlService.registerVibratorController(fakeController);
+ mVibratorControlService.unregisterVibratorController(fakeController);
+ assertThat(fakeController.isLinkedToDeath).isFalse();
+ }
+
+ @Test
+ public void testUnregisterVibratorController_providingAnInvalidController_ignoresRequest()
+ throws RemoteException {
+ FakeVibratorController fakeController1 = new FakeVibratorController();
+ FakeVibratorController fakeController2 = new FakeVibratorController();
+ mVibratorControlService.registerVibratorController(fakeController1);
+
+ mVibratorControlService.unregisterVibratorController(fakeController2);
+ assertThat(fakeController1.isLinkedToDeath).isTrue();
+ }
+}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
new file mode 100644
index 000000000000..79abe21a301d
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.RemoteException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class VibratorControllerHolderTest {
+
+ private final FakeVibratorController mFakeVibratorController = new FakeVibratorController();
+ private VibratorControllerHolder mVibratorControllerHolder;
+
+ @Before
+ public void setUp() throws Exception {
+ mVibratorControllerHolder = new VibratorControllerHolder();
+ }
+
+ @Test
+ public void testSetVibratorController_linksVibratorControllerToDeath() throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ assertThat(mVibratorControllerHolder.getVibratorController())
+ .isEqualTo(mFakeVibratorController);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
+ }
+
+ @Test
+ public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath()
+ throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ mVibratorControllerHolder.setVibratorController(null);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
+ assertThat(mVibratorControllerHolder.getVibratorController()).isNull();
+ }
+
+ @Test
+ public void testBinderDied_withValidController_unlinksVibratorControllerToDeath()
+ throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ mVibratorControllerHolder.binderDied(mFakeVibratorController);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
+ assertThat(mVibratorControllerHolder.getVibratorController()).isNull();
+ }
+
+ @Test
+ public void testBinderDied_withInvalidController_ignoresRequest()
+ throws RemoteException {
+ mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
+ FakeVibratorController imposterVibratorController = new FakeVibratorController();
+ mVibratorControllerHolder.binderDied(imposterVibratorController);
+ assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
+ assertThat(mVibratorControllerHolder.getVibratorController())
+ .isEqualTo(mFakeVibratorController);
+ }
+}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 4e9bbe0a28fe..d6b2116e2682 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -307,9 +307,10 @@ public class VibratorManagerServiceTest {
@Override
void addService(String name, IBinder service) {
- Object serviceInstance = service;
- mExternalVibratorService =
- (VibratorManagerService.ExternalVibratorService) serviceInstance;
+ if (service instanceof VibratorManagerService.ExternalVibratorService) {
+ mExternalVibratorService =
+ (VibratorManagerService.ExternalVibratorService) service;
+ }
}
HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
new file mode 100644
index 000000000000..7e235870cedc
--- /dev/null
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.annotation.NonNull;
+import android.frameworks.vibrator.IVibratorController;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * Provides a fake implementation of {@link android.frameworks.vibrator.IVibratorController} for
+ * testing.
+ */
+public final class FakeVibratorController extends IVibratorController.Stub {
+
+ public boolean isLinkedToDeath = false;
+
+ @Override
+ public void requestVibrationParams(int i, long l, IBinder iBinder) throws RemoteException {
+
+ }
+
+ @Override
+ public int getInterfaceVersion() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public String getInterfaceHash() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
+ super.linkToDeath(recipient, flags);
+ isLinkedToDeath = true;
+ }
+
+ @Override
+ public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
+ isLinkedToDeath = false;
+ return super.unlinkToDeath(recipient, flags);
+ }
+}
diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp
index 744cb63f72b3..8a79fe443179 100644
--- a/services/tests/voiceinteractiontests/Android.bp
+++ b/services/tests/voiceinteractiontests/Android.bp
@@ -44,6 +44,7 @@ android_test {
"servicestests-core-utils",
"servicestests-utils-mockito-extended",
"truth",
+ "frameworks-base-testutils",
],
libs: [
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
new file mode 100644
index 000000000000..159c760992c6
--- /dev/null
+++ b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.voiceinteraction;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.Manifest;
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.PermissionEnforcer;
+import android.os.Process;
+import android.os.test.FakePermissionEnforcer;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.quality.Strictness;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SetSandboxedTrainingDataAllowedTest {
+
+ @Captor private ArgumentCaptor<Integer> mOpIdCaptor, mUidCaptor, mOpModeCaptor;
+
+ @Mock
+ private AppOpsManager mAppOpsManager;
+
+ @Mock
+ private VoiceInteractionManagerServiceImpl mVoiceInteractionManagerServiceImpl;
+
+ private FakePermissionEnforcer mPermissionEnforcer = new FakePermissionEnforcer();
+
+ private Context mContext;
+
+ private VoiceInteractionManagerService mVoiceInteractionManagerService;
+ private VoiceInteractionManagerService.VoiceInteractionManagerServiceStub
+ mVoiceInteractionManagerServiceStub;
+
+ private ApplicationInfo mApplicationInfo = new ApplicationInfo();
+
+ @Rule
+ public final ExtendedMockitoRule mExtendedMockitoRule =
+ new ExtendedMockitoRule.Builder(this)
+ .setStrictness(Strictness.WARN)
+ .mockStatic(LocalServices.class)
+ .mockStatic(PermissionEnforcer.class)
+ .build();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(ApplicationProvider.getApplicationContext());
+
+ doReturn(mPermissionEnforcer).when(() -> PermissionEnforcer.fromContext(any()));
+ doReturn(mock(PermissionManagerServiceInternal.class)).when(
+ () -> LocalServices.getService(PermissionManagerServiceInternal.class));
+ doReturn(mock(ActivityManagerInternal.class)).when(
+ () -> LocalServices.getService(ActivityManagerInternal.class));
+ doReturn(mock(UserManagerInternal.class)).when(
+ () -> LocalServices.getService(UserManagerInternal.class));
+ doReturn(mock(ActivityTaskManagerInternal.class)).when(
+ () -> LocalServices.getService(ActivityTaskManagerInternal.class));
+ doReturn(mock(LegacyPermissionManagerInternal.class)).when(
+ () -> LocalServices.getService(LegacyPermissionManagerInternal.class));
+ doReturn(mock(RoleManager.class)).when(mContext).getSystemService(RoleManager.class);
+ doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
+ doReturn(mApplicationInfo).when(mVoiceInteractionManagerServiceImpl).getApplicationInfo();
+
+ mVoiceInteractionManagerService = new VoiceInteractionManagerService(mContext);
+ mVoiceInteractionManagerServiceStub =
+ mVoiceInteractionManagerService.new VoiceInteractionManagerServiceStub();
+ mVoiceInteractionManagerServiceStub.mImpl = mVoiceInteractionManagerServiceImpl;
+ mPermissionEnforcer.grant(Manifest.permission.MANAGE_HOTWORD_DETECTION);
+ }
+
+ @Test
+ public void setShouldReceiveSandboxedTrainingData_currentAndPreinstalledAssistant_setsOp() {
+ // Set application info so current app is the current and preinstalled assistant.
+ mApplicationInfo.uid = Process.myUid();
+ mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+ mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
+ /* allowed= */ true);
+
+ verify(mAppOpsManager).setUidMode(mOpIdCaptor.capture(), mUidCaptor.capture(),
+ mOpModeCaptor.capture());
+ assertThat(mOpIdCaptor.getValue()).isEqualTo(
+ AppOpsManager.OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA);
+ assertThat(mOpModeCaptor.getValue()).isEqualTo(AppOpsManager.MODE_ALLOWED);
+ assertThat(mUidCaptor.getValue()).isEqualTo(Process.myUid());
+ }
+
+ @Test
+ public void setShouldReceiveSandboxedTrainingData_missingPermission_doesNotSetOp() {
+ // Set application info so current app is the current and preinstalled assistant.
+ mApplicationInfo.uid = Process.myUid();
+ mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+ // Simulate missing MANAGE_HOTWORD_DETECTION permission.
+ mPermissionEnforcer.revoke(Manifest.permission.MANAGE_HOTWORD_DETECTION);
+
+ assertThrows(SecurityException.class,
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
+ /* allowed= */ true));
+
+ verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void setShouldReceiveSandboxedTrainingData_notPreinstalledAssistant_doesNotSetOp() {
+ // Set application info so current app is not preinstalled assistant.
+ mApplicationInfo.uid = Process.myUid();
+ mApplicationInfo.flags = ApplicationInfo.FLAG_INSTALLED; // Does not contain FLAG_SYSTEM.
+
+ assertThrows(SecurityException.class,
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
+ /* allowed= */ true));
+
+ verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void setShouldReceiveSandboxedTrainingData_notCurrentAssistant_doesNotSetOp() {
+ // Set application info so current app is not current assistant.
+ mApplicationInfo.uid = Process.SHELL_UID; // Set current assistant uid to shell UID.
+ mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+ assertThrows(SecurityException.class,
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
+ /* allowed= */ true));
+
+ verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
index 8d236eda5dc5..0382ca0d9fec 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
@@ -61,6 +61,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
META_SHORTCUTS.append(KEYCODE_P, Intent.CATEGORY_APP_MUSIC);
META_SHORTCUTS.append(KEYCODE_S, Intent.CATEGORY_APP_MESSAGING);
}
+ private static final int ANY_DISPLAY_ID = 123;
@Before
public void setUp() {
@@ -96,8 +97,9 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
*/
@Test
public void testCtrlSpace() {
- sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SPACE}, 0);
- mPhoneWindowManager.assertSwitchKeyboardLayout(1);
+ sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SPACE}, /* duration= */ 0,
+ ANY_DISPLAY_ID);
+ mPhoneWindowManager.assertSwitchKeyboardLayout(/* direction= */ 1, ANY_DISPLAY_ID);
}
/**
@@ -105,8 +107,9 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
*/
@Test
public void testCtrlShiftSpace() {
- sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_SPACE}, 0);
- mPhoneWindowManager.assertSwitchKeyboardLayout(-1);
+ sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_SPACE},
+ /* duration= */ 0, ANY_DISPLAY_ID);
+ mPhoneWindowManager.assertSwitchKeyboardLayout(/* direction= */ -1, ANY_DISPLAY_ID);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 9cdec2588501..157d1627d993 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -114,7 +114,7 @@ class ShortcutKeyTestBase {
}
}
- void sendKeyCombination(int[] keyCodes, long durationMillis, boolean longPress) {
+ void sendKeyCombination(int[] keyCodes, long durationMillis, boolean longPress, int displayId) {
final long downTime = mPhoneWindowManager.getCurrentTime();
final int count = keyCodes.length;
int metaState = 0;
@@ -124,7 +124,7 @@ class ShortcutKeyTestBase {
final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode,
0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
- event.setDisplayId(DEFAULT_DISPLAY);
+ event.setDisplayId(displayId);
interceptKey(event);
// The order is important here, metaState could be updated and applied to the next key.
metaState |= MODIFIER.getOrDefault(keyCode, 0);
@@ -142,7 +142,7 @@ class ShortcutKeyTestBase {
KeyEvent.ACTION_DOWN, keyCode, 1 /*repeat*/, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
KeyEvent.FLAG_LONG_PRESS /*flags*/, InputDevice.SOURCE_KEYBOARD);
- nextDownEvent.setDisplayId(DEFAULT_DISPLAY);
+ nextDownEvent.setDisplayId(displayId);
interceptKey(nextDownEvent);
}
}
@@ -153,18 +153,23 @@ class ShortcutKeyTestBase {
final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
InputDevice.SOURCE_KEYBOARD);
- upEvent.setDisplayId(DEFAULT_DISPLAY);
+ upEvent.setDisplayId(displayId);
interceptKey(upEvent);
metaState &= ~MODIFIER.getOrDefault(keyCode, 0);
}
}
void sendKeyCombination(int[] keyCodes, long durationMillis) {
- sendKeyCombination(keyCodes, durationMillis, false /* longPress */);
+ sendKeyCombination(keyCodes, durationMillis, false /* longPress */, DEFAULT_DISPLAY);
+ }
+
+ void sendKeyCombination(int[] keyCodes, long durationMillis, int displayId) {
+ sendKeyCombination(keyCodes, durationMillis, false /* longPress */, displayId);
}
void sendLongPressKeyCombination(int[] keyCodes) {
- sendKeyCombination(keyCodes, ViewConfiguration.getLongPressTimeout(), true /* longPress */);
+ sendKeyCombination(keyCodes, ViewConfiguration.getLongPressTimeout(), true /* longPress */,
+ DEFAULT_DISPLAY);
}
void sendKey(int keyCode) {
@@ -172,7 +177,7 @@ class ShortcutKeyTestBase {
}
void sendKey(int keyCode, boolean longPress) {
- sendKeyCombination(new int[]{keyCode}, 0 /*durationMillis*/, longPress);
+ sendKeyCombination(new int[]{keyCode}, 0 /*durationMillis*/, longPress, DEFAULT_DISPLAY);
}
private void interceptKey(KeyEvent keyEvent) {
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index d057226836a3..0678210e1d2f 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -166,12 +166,34 @@ class TestPhoneWindowManager {
@Mock
private PhoneWindowManager.ButtonOverridePermissionChecker mButtonOverridePermissionChecker;
+ @Mock private IBinder mInputToken;
+ @Mock private IBinder mImeTargetWindowToken;
+
private StaticMockitoSession mMockitoSession;
private OffsettableClock mClock = new OffsettableClock();
private TestLooper mTestLooper = new TestLooper(() -> mClock.now());
private HandlerThread mHandlerThread;
private Handler mHandler;
+ private boolean mIsTalkBackEnabled;
+
+ class TestTalkbackShortcutController extends TalkbackShortcutController {
+ TestTalkbackShortcutController(Context context) {
+ super(context);
+ }
+
+ @Override
+ boolean toggleTalkback(int currentUserId) {
+ mIsTalkBackEnabled = !mIsTalkBackEnabled;
+ return mIsTalkBackEnabled;
+ }
+
+ @Override
+ boolean isTalkBackShortcutGestureEnabled() {
+ return true;
+ }
+ }
+
private class TestInjector extends PhoneWindowManager.Injector {
TestInjector(Context context, WindowManagerPolicy.WindowManagerFuncs funcs) {
super(context, funcs, mTestLooper.getLooper());
@@ -197,6 +219,10 @@ class TestPhoneWindowManager {
PhoneWindowManager.ButtonOverridePermissionChecker getButtonOverridePermissionChecker() {
return mButtonOverridePermissionChecker;
}
+
+ TalkbackShortcutController getTalkbackShortcutController() {
+ return new TestTalkbackShortcutController(mContext);
+ }
}
TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) {
@@ -304,6 +330,9 @@ class TestPhoneWindowManager {
doNothing().when(mPhoneWindowManager).finishedWakingUp(anyInt(), anyInt());
doNothing().when(mPhoneWindowManager).lockNow(any());
+ doReturn(mImeTargetWindowToken)
+ .when(mWindowManagerInternal).getTargetWindowTokenFromInputToken(mInputToken);
+
mPhoneWindowManager.init(new TestInjector(mContext, mWindowManagerFuncsImpl));
mPhoneWindowManager.systemReady();
mPhoneWindowManager.systemBooted();
@@ -342,12 +371,12 @@ class TestPhoneWindowManager {
}
long interceptKeyBeforeDispatching(KeyEvent event) {
- return mPhoneWindowManager.interceptKeyBeforeDispatching(null /*focusedToken*/,
- event, FLAG_INTERACTIVE);
+ return mPhoneWindowManager.interceptKeyBeforeDispatching(mInputToken, event,
+ FLAG_INTERACTIVE);
}
void dispatchUnhandledKey(KeyEvent event) {
- mPhoneWindowManager.dispatchUnhandledKey(null /*focusedToken*/, event, FLAG_INTERACTIVE);
+ mPhoneWindowManager.dispatchUnhandledKey(mInputToken, event, FLAG_INTERACTIVE);
}
long getCurrentTime() {
@@ -623,14 +652,16 @@ class TestPhoneWindowManager {
verify(mStatusBarManagerInternal).startAssist(any());
}
- void assertSwitchKeyboardLayout(int direction) {
+ void assertSwitchKeyboardLayout(int direction, int displayId) {
mTestLooper.dispatchAll();
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
- verify(mInputMethodManagerInternal).switchKeyboardLayout(eq(direction));
+ verify(mInputMethodManagerInternal).onSwitchKeyboardLayoutShortcut(eq(direction),
+ eq(displayId), eq(mImeTargetWindowToken));
verify(mWindowManagerFuncsImpl, never()).switchKeyboardLayout(anyInt(), anyInt());
} else {
verify(mWindowManagerFuncsImpl).switchKeyboardLayout(anyInt(), eq(direction));
- verify(mInputMethodManagerInternal, never()).switchKeyboardLayout(anyInt());
+ verify(mInputMethodManagerInternal, never())
+ .onSwitchKeyboardLayoutShortcut(anyInt(), anyInt(), any());
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 65e77dcd4ca9..d4ba3b25178d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -124,7 +124,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private void verifyOnActivityLaunched(ActivityRecord activity) {
final ArgumentCaptor<Long> idCaptor = ArgumentCaptor.forClass(Long.class);
verifyAsync(mLaunchObserver).onActivityLaunched(idCaptor.capture(),
- eq(activity.mActivityComponent), anyInt());
+ eq(activity.mActivityComponent), anyInt(), anyInt());
final long id = idCaptor.getValue();
setExpectedStartedId(id, activity);
mLastLaunchedIds.put(activity.mActivityComponent, id);
@@ -132,7 +132,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
verifyAsync(mLaunchObserver).onActivityLaunchFinished(eq(mExpectedStartedId),
- eq(activity.mActivityComponent), anyLong());
+ eq(activity.mActivityComponent), anyLong(), anyInt());
}
private void setExpectedStartedId(long id, Object reason) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 7aa46a62b0f1..85c6f9e9b2fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -123,6 +123,7 @@ import android.app.ICompatCameraControlCallback;
import android.app.PictureInPictureParams;
import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.DestroyActivityItem;
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.WindowStateResizeItem;
@@ -169,6 +170,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import java.util.ArrayList;
+import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -260,8 +262,18 @@ public class ActivityRecordTests extends WindowTestsBase {
final MutableBoolean pauseFound = new MutableBoolean(false);
doAnswer((InvocationOnMock invocationOnMock) -> {
final ClientTransaction transaction = invocationOnMock.getArgument(0);
- if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
- pauseFound.value = true;
+ final List<ClientTransactionItem> items = transaction.getTransactionItems();
+ if (items != null) {
+ for (ClientTransactionItem item : items) {
+ if (item instanceof PauseActivityItem) {
+ pauseFound.value = true;
+ break;
+ }
+ }
+ } else {
+ if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
+ pauseFound.value = true;
+ }
}
return null;
}).when(mClientLifecycleManager).scheduleTransaction(any());
@@ -279,6 +291,8 @@ public class ActivityRecordTests extends WindowTestsBase {
// If the activity is not focusable, it should move to paused.
activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
+ mClientLifecycleManager.dispatchPendingTransactions();
+
assertTrue(activity.isState(PAUSING));
assertTrue(pauseFound.value);
@@ -1239,7 +1253,7 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
- public void testFinishActivityIfPossible_sendResultImmediately() {
+ public void testFinishActivityIfPossible_sendResultImmediately() throws RemoteException {
// Create activity representing the source of the activity result.
final ComponentName sourceComponent = ComponentName.createRelative(
DEFAULT_COMPONENT_PACKAGE_NAME, ".SourceActivity");
@@ -1270,12 +1284,8 @@ public class ActivityRecordTests extends WindowTestsBase {
targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
- try {
- verify(mClientLifecycleManager, atLeastOnce()).scheduleTransaction(
- any(ClientTransaction.class));
- } catch (RemoteException ignored) {
- }
-
+ verify(mClientLifecycleManager, atLeastOnce()).scheduleTransactionItem(
+ any(), any(ClientTransactionItem.class));
assertNull(targetActivity.results);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 526201f9c1c6..670f9f697a5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -49,6 +49,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -195,7 +196,7 @@ public class ActivityStartInterceptorTest {
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(PLATFORM_PACKAGE_NAME);
+ .thenReturn(UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME));
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
@@ -227,9 +228,10 @@ public class ActivityStartInterceptorTest {
.setMessage("Test Message")
.setIcon(0x11110001)
.build();
+ UserPackage suspender = UserPackage.of(TEST_USER_ID, suspendingPackage);
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(suspendingPackage);
- when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspendingPackage,
+ .thenReturn(suspender);
+ when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspender,
TEST_USER_ID)).thenReturn(dialogInfo);
return dialogInfo;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 98055fa6f0d5..8a9c05d07b26 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -117,6 +117,7 @@ import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.DeviceConfigStateHelper;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;
+import com.android.server.pm.PackageArchiver;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
@@ -421,6 +422,7 @@ public class ActivityStarterTests extends WindowTestsBase {
doNothing().when(mMockPackageManager).grantImplicitAccess(
anyInt(), any(), anyInt(), anyInt(), anyBoolean());
doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
+ doReturn(mock(PackageArchiver.class)).when(mMockPackageManager).getPackageArchiver();
final Intent intent = new Intent();
intent.addFlags(launchFlags);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
index 04aa9815e698..7fdc5fc2cff6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
@@ -17,13 +17,15 @@
package com.android.server.wm;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -31,12 +33,15 @@ import android.app.IApplicationThread;
import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
+import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -47,30 +52,47 @@ import org.mockito.MockitoAnnotations;
* Build/Install/Run:
* atest WmTests:ClientLifecycleManagerTests
*/
+// Suppress GuardedBy warning on unit tests
+@SuppressWarnings("GuardedBy")
@SmallTest
@Presubmit
public class ClientLifecycleManagerTests {
+ @Rule(order = 0)
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Rule(order = 1)
+ public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule();
+
+ @Mock
+ private IBinder mClientBinder;
@Mock
private IApplicationThread mClient;
@Mock
private IApplicationThread.Stub mNonBinderClient;
@Mock
+ private ClientTransaction mTransaction;
+ @Mock
private ClientTransactionItem mTransactionItem;
@Mock
private ActivityLifecycleItem mLifecycleItem;
@Captor
private ArgumentCaptor<ClientTransaction> mTransactionCaptor;
+ private WindowManagerService mWms;
private ClientLifecycleManager mLifecycleManager;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ mWms = mSystemServices.getWindowManagerService();
mLifecycleManager = spy(new ClientLifecycleManager());
+ mLifecycleManager.setWindowManager(mWms);
doReturn(true).when(mLifecycleItem).isActivityLifecycleItem();
+ doReturn(mClientBinder).when(mClient).asBinder();
+ doReturn(mNonBinderClient).when(mNonBinderClient).asBinder();
}
@Test
@@ -92,9 +114,11 @@ public class ClientLifecycleManagerTests {
}
@Test
- public void testScheduleTransactionItem() throws RemoteException {
- doNothing().when(mLifecycleManager).scheduleTransaction(any());
- mLifecycleManager.scheduleTransactionItem(mClient, mTransactionItem);
+ public void testScheduleTransactionItem_notBundle() throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mTransactionItem);
verify(mLifecycleManager).scheduleTransaction(mTransactionCaptor.capture());
ClientTransaction transaction = mTransactionCaptor.getValue();
@@ -104,7 +128,7 @@ public class ClientLifecycleManagerTests {
assertNull(transaction.getTransactionItems());
clearInvocations(mLifecycleManager);
- mLifecycleManager.scheduleTransactionItem(mClient, mLifecycleItem);
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem);
verify(mLifecycleManager).scheduleTransaction(mTransactionCaptor.capture());
transaction = mTransactionCaptor.getValue();
@@ -113,9 +137,54 @@ public class ClientLifecycleManagerTests {
}
@Test
- public void testScheduleTransactionAndLifecycleItems() throws RemoteException {
- doNothing().when(mLifecycleManager).scheduleTransaction(any());
- mLifecycleManager.scheduleTransactionAndLifecycleItems(mClient, mTransactionItem,
+ public void testScheduleTransactionItem() throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+ spyOn(mWms.mWindowPlacerLocked);
+ doReturn(true).when(mWms.mWindowPlacerLocked).isTraversalScheduled();
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mTransactionItem);
+
+ // When there is traversal scheduled, add transaction items to pending.
+ assertEquals(1, mLifecycleManager.mPendingTransactions.size());
+ ClientTransaction transaction =
+ mLifecycleManager.mPendingTransactions.get(mNonBinderClient);
+ assertEquals(1, transaction.getTransactionItems().size());
+ assertEquals(mTransactionItem, transaction.getTransactionItems().get(0));
+ assertNull(transaction.getCallbacks());
+ assertNull(transaction.getLifecycleStateRequest());
+ verify(mLifecycleManager, never()).scheduleTransaction(any());
+
+ // Add new transaction item to the existing pending.
+ clearInvocations(mLifecycleManager);
+ mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem);
+
+ assertEquals(1, mLifecycleManager.mPendingTransactions.size());
+ transaction = mLifecycleManager.mPendingTransactions.get(mNonBinderClient);
+ assertEquals(2, transaction.getTransactionItems().size());
+ assertEquals(mTransactionItem, transaction.getTransactionItems().get(0));
+ assertEquals(mLifecycleItem, transaction.getTransactionItems().get(1));
+ assertNull(transaction.getCallbacks());
+ assertNull(transaction.getLifecycleStateRequest());
+ verify(mLifecycleManager, never()).scheduleTransaction(any());
+ }
+
+ @Test
+ public void testScheduleTransactionItemUnlocked() throws RemoteException {
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionItemUnlocked(mNonBinderClient, mTransactionItem);
+
+ // Dispatch immediately.
+ assertTrue(mLifecycleManager.mPendingTransactions.isEmpty());
+ verify(mLifecycleManager).scheduleTransaction(any());
+ }
+
+ @Test
+ public void testScheduleTransactionAndLifecycleItems_notBundle() throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionAndLifecycleItems(mNonBinderClient, mTransactionItem,
mLifecycleItem);
verify(mLifecycleManager).scheduleTransaction(mTransactionCaptor.capture());
@@ -124,4 +193,36 @@ public class ClientLifecycleManagerTests {
assertEquals(mTransactionItem, transaction.getCallbacks().get(0));
assertEquals(mLifecycleItem, transaction.getLifecycleStateRequest());
}
+
+ @Test
+ public void testScheduleTransactionAndLifecycleItems() throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+ spyOn(mWms.mWindowPlacerLocked);
+ doReturn(true).when(mWms.mWindowPlacerLocked).isTraversalScheduled();
+
+ // Use non binder client to get non-recycled ClientTransaction.
+ mLifecycleManager.scheduleTransactionAndLifecycleItems(mNonBinderClient, mTransactionItem,
+ mLifecycleItem);
+
+ assertEquals(1, mLifecycleManager.mPendingTransactions.size());
+ final ClientTransaction transaction =
+ mLifecycleManager.mPendingTransactions.get(mNonBinderClient);
+ assertEquals(2, transaction.getTransactionItems().size());
+ assertEquals(mTransactionItem, transaction.getTransactionItems().get(0));
+ assertEquals(mLifecycleItem, transaction.getTransactionItems().get(1));
+ assertNull(transaction.getCallbacks());
+ assertNull(transaction.getLifecycleStateRequest());
+ verify(mLifecycleManager, never()).scheduleTransaction(any());
+ }
+
+ @Test
+ public void testDispatchPendingTransactions() throws RemoteException {
+ mLifecycleManager.mPendingTransactions.put(mClientBinder, mTransaction);
+
+ mLifecycleManager.dispatchPendingTransactions();
+
+ assertTrue(mLifecycleManager.mPendingTransactions.isEmpty());
+ verify(mTransaction).schedule();
+ verify(mTransaction).recycle();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 71d2504e1746..dfe79bf1e3e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -993,7 +993,9 @@ public class DisplayContentTests extends WindowTestsBase {
dc.getDisplayPolicy().getDecorInsetsInfo(ROTATION_0, dc.mBaseDisplayHeight,
dc.mBaseDisplayWidth).mConfigFrame.set(0, 0, 1000, 990);
dc.computeScreenConfiguration(config, ROTATION_0);
+ dc.onRequestedOverrideConfigurationChanged(config);
assertEquals(Configuration.ORIENTATION_LANDSCAPE, config.orientation);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getNaturalOrientation());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 50fe0425fe9c..1fb7cd8e6e1c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -553,7 +553,7 @@ public class DragDropControllerTests extends WindowTestsBase {
assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(),
new InputChannel(), true /* isDragDrop */));
mToken = mTarget.performDrag(TEST_PID, 0, mWindow.mClient,
- flag, surface, 0, 0, 0, 0, 0, data);
+ flag, surface, 0, 0, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
r.run();
@@ -575,7 +575,7 @@ public class DragDropControllerTests extends WindowTestsBase {
private void startA11yDrag(int flags, ClipData data, Runnable r) {
mToken = mTarget.performDrag(0, 0, mWindow.mClient,
- flags | View.DRAG_FLAG_ACCESSIBILITY_ACTION, null, 0, 0, 0, 0, 0, data);
+ flags | View.DRAG_FLAG_ACCESSIBILITY_ACTION, null, 0, 0, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
r.run();
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3d2340cca378..72db7fecb8ac 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2278,6 +2278,12 @@ public class UsageStatsService extends SystemService implements
"Only the system or holders of the REPORT_USAGE_STATS"
+ " permission are allowed to call reportUserInteraction");
}
+ if (userId != UserHandle.getCallingUserId()) {
+ // Cross-user event reporting.
+ getContext().enforceCallingPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "Caller doesn't have INTERACT_ACROSS_USERS_FULL permission");
+ }
} else {
if (!isCallingUidSystem()) {
throw new SecurityException("Only system is allowed to call"
@@ -2287,7 +2293,8 @@ public class UsageStatsService extends SystemService implements
// Verify if this package exists before reporting an event for it.
if (mPackageManagerInternal.getPackageUid(packageName, 0, userId) < 0) {
- throw new IllegalArgumentException("Package " + packageName + "not exist!");
+ throw new IllegalArgumentException("Package " + packageName
+ + " does not exist!");
}
final Event event = new Event(USER_INTERACTION, SystemClock.elapsedRealtime());
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index b214591610de..c902d4597571 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1569,13 +1569,13 @@ public class VoiceInteractionManagerService extends SystemService {
@Override
@EnforcePermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION)
- public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
- super.setIsReceiveSandboxedTrainingDataAllowed_enforcePermission();
+ public void setShouldReceiveSandboxedTrainingData(boolean allowed) {
+ super.setShouldReceiveSandboxedTrainingData_enforcePermission();
synchronized (this) {
if (mImpl == null) {
throw new IllegalStateException(
- "setIsReceiveSandboxedTrainingDataAllowed without running voice "
+ "setShouldReceiveSandboxedTrainingData without running voice "
+ "interaction service");
}
@@ -2273,9 +2273,9 @@ public class VoiceInteractionManagerService extends SystemService {
private boolean isCallerPreinstalledAssistant() {
return mImpl != null
- && mImpl.mInfo.getServiceInfo().applicationInfo.uid == Binder.getCallingUid()
- && (mImpl.mInfo.getServiceInfo().applicationInfo.isSystemApp()
- || mImpl.mInfo.getServiceInfo().applicationInfo.isUpdatedSystemApp());
+ && mImpl.getApplicationInfo().uid == Binder.getCallingUid()
+ && (mImpl.getApplicationInfo().isSystemApp()
+ || mImpl.getApplicationInfo().isUpdatedSystemApp());
}
private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 3c4b58fa2b69..7e0cbad1e828 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -40,6 +40,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
@@ -540,6 +541,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
return mInfo.getSupportsLocalInteraction();
}
+ public ApplicationInfo getApplicationInfo() {
+ return mInfo.getServiceInfo().applicationInfo;
+ }
+
public void startListeningVisibleActivityChangedLocked(@NonNull IBinder token) {
if (DEBUG) {
Slog.d(TAG, "startListeningVisibleActivityChangedLocked: token=" + token);
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index eac4d1682aa9..cc768bc00250 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -16,12 +16,16 @@
package android.telephony;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
+import android.telephony.TelephonyManager.CarrierRestrictionStatus;
+
+import com.android.internal.telephony.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -104,7 +108,7 @@ public final class CarrierRestrictionRules implements Parcelable {
private int mCarrierRestrictionDefault;
@MultiSimPolicy
private int mMultiSimPolicy;
- @TelephonyManager.CarrierRestrictionStatus
+ @CarrierRestrictionStatus
private int mCarrierRestrictionStatus;
private CarrierRestrictionRules() {
@@ -293,8 +297,22 @@ public final class CarrierRestrictionRules implements Parcelable {
return true;
}
- /** @hide */
- public int getCarrierRestrictionStatus() {
+ /**
+ * Get the carrier restriction status of the device.
+ * The return value of the API is as follows.
+ * <ul>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER}
+ * if the caller and the device locked by the network are same</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_RESTRICTED} if the
+ * caller and the device locked by the network are different</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED} if the
+ * device is not locked</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_UNKNOWN} if the device
+ * locking state is unavailable or radio does not supports the feature</li>
+ * </ul>
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_RESTRICTION_STATUS)
+ public @CarrierRestrictionStatus int getCarrierRestrictionStatus() {
return mCarrierRestrictionStatus;
}
diff --git a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java
index a004cc3a1642..25063606228c 100644
--- a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java
+++ b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.WorkerThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.text.Editable;
@@ -39,6 +40,9 @@ import java.util.Locale;
* </ul>
* <p>
* The formatting will be restarted once the text is cleared.
+ *
+ * @deprecated This is a thin wrapper on a `libphonenumber` `AsYouTypeFormatter`; it is recommended
+ * to use that instead.
*/
public class PhoneNumberFormattingTextWatcher implements TextWatcher {
@@ -69,6 +73,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher {
* @param countryCode the ISO 3166-1 two-letter country code that indicates the country/region
* where the phone number is being entered.
*/
+ @WorkerThread
public PhoneNumberFormattingTextWatcher(String countryCode) {
if (countryCode == null) throw new IllegalArgumentException();
mFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index b356fde53417..326b6f5af613 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1508,8 +1508,14 @@ public class SubscriptionManager {
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
if (listener == null) return;
- addOnSubscriptionsChangedListener(
- new HandlerExecutor(new Handler(listener.getCreatorLooper())), listener);
+ Looper looper = listener.getCreatorLooper();
+ if (looper == null) {
+ throw new RuntimeException(
+ "Can't create handler inside thread " + Thread.currentThread()
+ + " that has not called Looper.prepare()");
+ }
+
+ addOnSubscriptionsChangedListener(new HandlerExecutor(new Handler(looper)), listener);
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b96914e59c0e..5520cf6f50ba 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -18009,6 +18009,64 @@ public class TelephonyManager {
}
/**
+ * Enable or disable notifications sent for cellular identifier disclosure events.
+ *
+ * Disclosure events are defined as instances where a device has sent a cellular identifier
+ * on the Non-access stratum (NAS) before a security context is established. As a result the
+ * identifier is sent in the clear, which has privacy implications for the user.
+ *
+ * @param enable if notifications about disclosure events should be enabled
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support this feature.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY)
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ @SystemApi
+ public void setEnableCellularIdentifierDisclosureNotifications(boolean enable) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setEnableCellularIdentifierDisclosureNotifications(enable);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setEnableCellularIdentifierDisclosureNotifications RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get whether or not cellular identifier disclosure notifications are enabled.
+ *
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support this feature.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY)
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi
+ public boolean isCellularIdentifierDisclosureNotificationsEnabled() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isCellularIdentifierDisclosureNotificationsEnabled();
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "isCellularIdentifierDisclosureNotificationsEnabled RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
* Get current cell broadcast message identifier ranges.
*
* @throws SecurityException if the caller does not have the required permission
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 3e8787281f85..8679bd4baf2e 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1866,7 +1866,7 @@ public class ApnSetting implements Parcelable {
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
private boolean mAlwaysOn;
- private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR;
+ private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR | INFRASTRUCTURE_SATELLITE;
private boolean mEsimBootstrapProvisioning;
/**
diff --git a/telephony/java/android/telephony/satellite/NtnSignalStrength.java b/telephony/java/android/telephony/satellite/NtnSignalStrength.java
index 16d765455d21..2fec423d1d65 100644
--- a/telephony/java/android/telephony/satellite/NtnSignalStrength.java
+++ b/telephony/java/android/telephony/satellite/NtnSignalStrength.java
@@ -86,6 +86,9 @@ public final class NtnSignalStrength implements Parcelable {
readFromParcel(in);
}
+ /**
+ * Returns notified non-terrestrial network signal strength level.
+ */
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
@NtnSignalStrengthLevel public int getLevel() {
return mLevel;
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 71786b308937..e09bd201f93e 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -34,6 +34,7 @@ import android.os.ICancellationSignal;
import android.os.OutcomeReceiver;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceSpecificException;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyFrameworkInitializer;
@@ -1919,7 +1920,6 @@ public final class SatelliteManager {
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @NonNull
public void requestNtnSignalStrength(@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<NtnSignalStrength, SatelliteException> callback) {
Objects.requireNonNull(executor);
@@ -1962,6 +1962,8 @@ public final class SatelliteManager {
/**
* Registers for NTN signal strength changed from satellite modem.
+ * If the registration operation is not successful, a {@link SatelliteException} that contains
+ * {@link SatelliteResult} will be thrown.
*
* <p>
* Note: This API is specifically designed for OEM enabled satellite connectivity only.
@@ -1973,16 +1975,14 @@ public final class SatelliteManager {
* @param executor The executor on which the callback will be called.
* @param callback The callback to handle the NTN signal strength changed event.
*
- * @return The {@link SatelliteResult} result of the operation.
- *
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws SatelliteException if the callback registration operation fails.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @SatelliteResult public int registerForNtnSignalStrengthChanged(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull NtnSignalStrengthCallback callback) {
+ public void registerForNtnSignalStrengthChanged(@NonNull @CallbackExecutor Executor executor,
+ @NonNull NtnSignalStrengthCallback callback) throws SatelliteException {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -1999,16 +1999,18 @@ public final class SatelliteManager {
ntnSignalStrength)));
}
};
+ telephony.registerForNtnSignalStrengthChanged(mSubId, internalCallback);
sNtnSignalStrengthCallbackMap.put(callback, internalCallback);
- return telephony.registerForNtnSignalStrengthChanged(mSubId, internalCallback);
} else {
throw new IllegalStateException("Telephony service is null.");
}
+ } catch (ServiceSpecificException ex) {
+ logd("registerForNtnSignalStrengthChanged() registration fails: " + ex.errorCode);
+ throw new SatelliteException(ex.errorCode);
} catch (RemoteException ex) {
loge("registerForNtnSignalStrengthChanged() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_RESULT_REQUEST_FAILED;
}
/**
@@ -2025,6 +2027,8 @@ public final class SatelliteManager {
* {@link #registerForNtnSignalStrengthChanged(Executor, NtnSignalStrengthCallback)}.
*
* @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalArgumentException if the callback is not valid or has already been
+ * unregistered.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@@ -2041,6 +2045,7 @@ public final class SatelliteManager {
telephony.unregisterForNtnSignalStrengthChanged(mSubId, internalCallback);
} else {
loge("unregisterForNtnSignalStrengthChanged: No internal callback.");
+ throw new IllegalArgumentException("callback is not valid");
}
} else {
throw new IllegalStateException("Telephony service is null.");
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4c53f8ab9bca..37752d0cecd8 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3101,16 +3101,21 @@ interface ITelephony {
void requestNtnSignalStrength(int subId, in ResultReceiver receiver);
/**
- * Registers for NTN signal strength changed from satellite modem.
+ * Registers for NTN signal strength changed from satellite modem. If the registration operation
+ * is not successful, a {@link SatelliteException} that contains {@link SatelliteResult} will be
+ * thrown.
*
* @param subId The subId of the subscription to request for.
- * @param callback The callback to handle the NTN signal strength changed event.
- *
- * @return The {@link SatelliteResult} result of the operation.
+ * @param callback The callback to handle the NTN signal strength changed event. If the
+ * operation is successful, {@link NtnSignalStrengthCallback#onNtnSignalStrengthChanged(
+ * NtnSignalStrength)} will return an instance of {@link NtnSignalStrength} with a value of
+ * {@link NtnSignalStrength.NtnSignalStrengthLevel} when the signal strength of non-terrestrial
+ * network has changed.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForNtnSignalStrengthChanged(int subId, in INtnSignalStrengthCallback callback);
+ void registerForNtnSignalStrengthChanged(int subId,
+ in INtnSignalStrengthCallback callback);
/**
* Unregisters for NTN signal strength changed from satellite modem.
@@ -3159,4 +3164,37 @@ interface ITelephony {
* @return {@code true} if the operation is successful, {@code false} otherwise.
*/
boolean setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode);
+
+ /**
+ * Enable or disable notifications sent for cellular identifier disclosure events.
+ *
+ * Disclosure events are defined as instances where a device has sent a cellular identifier
+ * on the Non-access stratum (NAS) before a security context is established. As a result the
+ * identifier is sent in the clear, which has privacy implications for the user.
+ *
+ * <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE</p>
+ *
+ * @param enabled if notifications about disclosure events should be enabled
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support this feature.
+ * @hide
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.MODIFY_PHONE_STATE)")
+ void setEnableCellularIdentifierDisclosureNotifications(boolean enable);
+
+ /**
+ * Get whether or not cellular identifier disclosure notifications are enabled.
+ *
+ * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE</p>
+ *
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support this feature.
+ * @hide
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)")
+ boolean isCellularIdentifierDisclosureNotificationsEnabled();
}
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index 12a57d52491a..c8cac8fa2c82 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -25,6 +25,7 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
@@ -142,7 +143,7 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :
}
/** During the transition Secondary Activity shrinks to the bottom right corner. */
- @Presubmit
+ @FlakyTest(bugId = 315605409)
@Test
fun secondaryLayerShrinks() {
flicker.assertLayers {
diff --git a/tools/aapt2/integration-tests/SymlinkTest/Android.bp b/tools/aapt2/integration-tests/SymlinkTest/Android.bp
index 15a6a207d6d1..6fcdf1c77704 100644
--- a/tools/aapt2/integration-tests/SymlinkTest/Android.bp
+++ b/tools/aapt2/integration-tests/SymlinkTest/Android.bp
@@ -27,4 +27,7 @@ android_test {
name: "AaptSymlinkTest",
sdk_version: "current",
use_resource_processor: false,
+ compile_data: [
+ "targets/*",
+ ],
}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
index 068dfe8f3d11..a1356237e5a4 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/LongArrayMultiStateCounter_host.java
@@ -100,6 +100,10 @@ public class LongArrayMultiStateCounter_host {
mLastStateChangeTimestampMs = timestampMs;
}
+ public void setValue(int state, long[] values) {
+ System.arraycopy(values, 0, mStates[state].mCounter, 0, mArrayLength);
+ }
+
public void updateValue(long[] values, long timestampMs) {
if (mEnabled || mLastUpdateTimestampMs < mLastStateChangeTimestampMs) {
if (timestampMs < mLastStateChangeTimestampMs) {
@@ -306,6 +310,11 @@ public class LongArrayMultiStateCounter_host {
return getInstance(instanceId).mArrayLength;
}
+ public static void native_setValues(long instanceId, int state, long containerInstanceId) {
+ getInstance(instanceId).setValue(state,
+ LongArrayContainer_host.getInstance(containerInstanceId));
+ }
+
public static void native_updateValues(long instanceId, long containerInstanceId,
long timestampMs) {
getInstance(instanceId).updateValue(
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 3bcabcb01c5e..d63bff6f4da3 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
@@ -343,6 +343,28 @@ public class Parcel_host {
p.mPos += length;
p.updateSize();
}
+ public static int nativeCompareData(long thisNativePtr, long otherNativePtr) {
+ var a = getInstance(thisNativePtr);
+ var b = getInstance(otherNativePtr);
+ if ((a.mSize == b.mSize) && Arrays.equals(a.mBuffer, b.mBuffer)) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ public static boolean nativeCompareDataInRange(
+ long ptrA, int offsetA, long ptrB, int offsetB, int length) {
+ var a = getInstance(ptrA);
+ var b = getInstance(ptrB);
+ if (offsetA < 0 || offsetA + length > a.mSize) {
+ throw new IllegalArgumentException();
+ }
+ if (offsetB < 0 || offsetB + length > b.mSize) {
+ throw new IllegalArgumentException();
+ }
+ return Arrays.equals(Arrays.copyOfRange(a.mBuffer, offsetA, offsetA + length),
+ Arrays.copyOfRange(b.mBuffer, offsetB, offsetB + length));
+ }
public static void nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int srcOffset, int length) {
var dst = getInstance(thisNativePtr);