summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--StubLibraries.bp94
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java56
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobHandle.java2
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java2
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java244
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java6
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java343
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java2
-rw-r--r--apex/jobscheduler/framework/java/android/app/AlarmManager.java35
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java24
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java38
-rw-r--r--boot/hiddenapi/OWNERS4
-rw-r--r--core/api/current.txt6
-rw-r--r--core/api/module-lib-current.txt6
-rw-r--r--core/api/system-current.txt12
-rw-r--r--core/api/test-current.txt9
-rw-r--r--core/java/android/app/ActivityManager.java3
-rw-r--r--core/java/android/app/ActivityThread.java3
-rw-r--r--core/java/android/app/BroadcastOptions.java2
-rw-r--r--core/java/android/app/ContextImpl.java85
-rw-r--r--core/java/android/app/IActivityManager.aidl2
-rw-r--r--core/java/android/app/Notification.java110
-rw-r--r--core/java/android/app/Service.java13
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java106
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/app/admin/ParcelableGranteeMap.aidl19
-rw-r--r--core/java/android/app/admin/ParcelableGranteeMap.java85
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl1
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java14
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java4
-rw-r--r--core/java/android/bluetooth/OobData.java2
-rw-r--r--core/java/android/content/Context.java11
-rw-r--r--core/java/android/content/ContextWrapper.java7
-rw-r--r--core/java/android/content/Intent.java1
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedAttribution.java8
-rw-r--r--core/java/android/content/pm/verify/domain/DomainVerificationManager.java8
-rw-r--r--core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl4
-rw-r--r--core/java/android/net/VpnManager.java4
-rw-r--r--core/java/android/net/vcn/VcnGatewayConnectionConfig.java7
-rw-r--r--core/java/android/os/BatteryConsumer.java55
-rw-r--r--core/java/android/os/BatteryUsageStats.java72
-rw-r--r--core/java/android/os/PowerComponents.java56
-rw-r--r--core/java/android/os/RecoverySystem.java5
-rw-r--r--core/java/android/os/SystemBatteryConsumer.java11
-rw-r--r--core/java/android/os/UidBatteryConsumer.java4
-rw-r--r--core/java/android/os/UserBatteryConsumer.java4
-rw-r--r--core/java/android/provider/CallLog.java18
-rw-r--r--core/java/android/provider/Settings.java14
-rw-r--r--core/java/android/uwb/UwbManager.java4
-rw-r--r--core/java/android/view/SurfaceControl.java22
-rw-r--r--core/java/android/view/ViewRootImpl.java27
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java4
-rw-r--r--core/java/android/view/textclassifier/TextClassifierEvent.java10
-rw-r--r--core/java/android/view/translation/UiTranslationController.java20
-rw-r--r--core/java/android/widget/EdgeEffect.java24
-rw-r--r--core/java/android/widget/TextViewTranslationCallback.java6
-rw-r--r--core/java/android/window/WindowContextController.java1
-rw-r--r--core/java/android/window/WindowProviderService.java138
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java33
-rw-r--r--core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java4
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java34
-rw-r--r--core/java/com/android/internal/os/BatteryUsageStatsProvider.java8
-rw-r--r--core/java/com/android/internal/os/BinderLatencyObserver.java144
-rw-r--r--core/java/com/android/internal/os/IdlePowerCalculator.java4
-rw-r--r--core/java/com/android/internal/os/MemoryPowerCalculator.java4
-rw-r--r--core/java/com/android/internal/os/PhonePowerCalculator.java4
-rw-r--r--core/java/com/android/internal/os/ScreenPowerCalculator.java4
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyStats.java31
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl3
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java39
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java13
-rw-r--r--core/java/com/android/internal/widget/LockSettingsInternal.java30
-rw-r--r--core/java/com/android/internal/widget/MessagingGroup.java39
-rw-r--r--core/java/com/android/internal/widget/MessagingLayout.java152
-rw-r--r--core/java/com/android/internal/widget/NotificationExpandButton.java16
-rw-r--r--core/java/com/android/internal/widget/PeopleHelper.java58
-rw-r--r--core/jni/android_view_SurfaceControl.cpp9
-rw-r--r--core/proto/android/internal/binder_latency.proto77
-rw-r--r--core/res/res/drawable/ic_call_answer_video.xml27
-rw-r--r--core/res/res/layout/notification_expand_button.xml2
-rw-r--r--core/res/res/layout/notification_template_conversation_header.xml30
-rw-r--r--core/res/res/layout/notification_template_conversation_icon_container.xml4
-rw-r--r--core/res/res/layout/notification_template_material_big_messaging.xml62
-rw-r--r--core/res/res/layout/notification_template_material_call.xml2
-rw-r--r--core/res/res/layout/notification_template_material_heads_up_base.xml2
-rw-r--r--core/res/res/layout/notification_template_material_messaging.xml200
-rw-r--r--core/res/res/layout/notification_top_line_views.xml3
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/dimens.xml14
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml9
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_amp_24.xml10
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_calculate_24.xml25
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_custom_24.xml10
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_timer_24.xml10
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml15
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml32
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml21
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java350
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java152
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java56
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java134
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java17
-rw-r--r--core/tests/coretests/src/android/window/WindowContextTest.java45
-rw-r--r--core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java12
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java12
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java21
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java131
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java12
-rw-r--r--core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java85
-rw-r--r--data/etc/privapp-permissions-platform.xml3
-rw-r--r--data/etc/services.core.protolog.json6
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_menu_background.xml22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt14
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt14
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt6
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp12
-rwxr-xr-xlibs/hwui/tests/scripts/skp-capture.sh4
-rw-r--r--media/java/android/media/MediaDrm.java10
-rw-r--r--media/java/android/media/session/PlaybackState.java18
-rw-r--r--packages/Connectivity/framework/api/system-current.txt1
-rw-r--r--packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl1
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkAgent.java29
-rw-r--r--packages/Connectivity/framework/src/android/net/VpnTransportInfo.java5
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml4
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values/themes.xml2
-rw-r--r--packages/Shell/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt6
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml1
-rw-r--r--packages/SystemUI/res/drawable/qs_detail_background.xml4
-rw-r--r--packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml4
-rw-r--r--packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml4
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml14
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java54
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java64
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java101
-rw-r--r--packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java2
-rw-r--r--services/Android.bp2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java36
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java6
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java14
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java15
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java39
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java69
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java6
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java32
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java21
-rw-r--r--services/core/java/com/android/server/am/MeasuredEnergySnapshot.java32
-rw-r--r--services/core/java/com/android/server/am/PreBootBroadcaster.java2
-rw-r--r--services/core/java/com/android/server/am/UserController.java4
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java3
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java120
-rw-r--r--services/core/java/com/android/server/biometrics/PreAuthInfo.java12
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java93
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java79
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java62
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkRanker.java13
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java1
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java11
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java4
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java4
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowManager.java79
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java2
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java18
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java16
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java2
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java1
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java4
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java3
-rw-r--r--services/core/java/com/android/server/power/FaceDownDetector.java4
-rw-r--r--services/core/java/com/android/server/recoverysystem/RecoverySystemService.java92
-rw-r--r--services/core/java/com/android/server/timedetector/EnvironmentImpl.java111
-rw-r--r--services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java141
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java42
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java6
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java23
-rw-r--r--services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java2
-rw-r--r--services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java4
-rw-r--r--services/core/java/com/android/server/trust/OWNERS2
-rw-r--r--services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java12
-rw-r--r--services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java13
-rw-r--r--services/core/java/com/android/server/vcn/Vcn.java187
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java33
-rw-r--r--services/core/java/com/android/server/vcn/VcnNetworkProvider.java161
-rw-r--r--services/core/java/com/android/server/vcn/util/MtuUtils.java1
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java41
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java10
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java8
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java35
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java16
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java2
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java16
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java21
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java34
-rw-r--r--services/java/com/android/server/SystemServer.java7
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java13
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java26
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java39
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java102
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java69
-rw-r--r--services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java299
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java112
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java73
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java40
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java13
-rw-r--r--services/uwb/Android.bp26
-rw-r--r--services/uwb/java/com/android/server/uwb/UwbInjector.java48
-rw-r--r--services/uwb/java/com/android/server/uwb/UwbService.java42
-rw-r--r--services/uwb/java/com/android/server/uwb/UwbServiceImpl.java288
-rw-r--r--telephony/java/android/telephony/AccessNetworkConstants.java4
-rw-r--r--telephony/java/android/telephony/AccessNetworkUtils.java13
-rw-r--r--telephony/java/android/telephony/ims/SipMessage.java17
-rw-r--r--tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt49
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt26
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt20
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt20
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt8
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt7
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt14
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt12
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt12
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt27
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt19
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt20
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt26
-rw-r--r--tests/UpdatableSystemFontTest/AndroidTest.xml5
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp32
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml23
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java40
-rw-r--r--tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java96
-rw-r--r--tests/net/integration/Android.bp2
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java3
-rw-r--r--tests/net/java/com/android/server/connectivity/LingerMonitorTest.java4
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java10
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java1
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java28
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java1
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java84
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnTest.java146
-rwxr-xr-xtools/hiddenapi/checksorted_sha.sh4
-rwxr-xr-xtools/hiddenapi/exclude.sh1
320 files changed, 6665 insertions, 2407 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 284e807bfc45..23dc7207343c 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -123,13 +123,19 @@ droidstubs {
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/public/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/public/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -137,21 +143,18 @@ droidstubs {
],
}
-priv_apps =
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+priv_apps = " --show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\)"
-priv_apps_in_stubs =
- " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+priv_apps_in_stubs = " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\)"
test = " --show-annotation android.annotation.TestApi"
-module_libs =
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+module_libs = " --show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
"\\)"
droidstubs {
@@ -166,7 +169,7 @@ droidstubs {
last_released: {
api_file: ":android-non-updatable.api.system.latest",
removed_api_file: ":android-non-updatable-removed.api.system.latest",
- baseline_file: ":android-non-updatable-incompatibilities.api.system.latest"
+ baseline_file: ":android-non-updatable-incompatibilities.api.system.latest",
},
api_lint: {
enabled: true,
@@ -176,13 +179,19 @@ droidstubs {
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -206,25 +215,37 @@ droidstubs {
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "android.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "removed.txt",
tag: ".removed-api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -252,13 +273,19 @@ droidstubs {
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/module-lib/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/module-lib/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -318,10 +345,13 @@ java_defaults {
java_version: "1.8",
compile_dex: true,
dist: {
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
tag: ".jar",
dest: "android-non-updatable.jar",
- }
+ },
}
java_library_static {
@@ -337,7 +367,7 @@ java_library_static {
java_library_static {
name: "android-non-updatable.stubs.system",
defaults: ["android-non-updatable_defaults_stubs_current"],
- srcs: [ ":system-api-stubs-docs-non-updatable" ],
+ srcs: [":system-api-stubs-docs-non-updatable"],
libs: modules_system_stubs,
dist: {
dir: "apistubs/android/system",
@@ -380,7 +410,10 @@ java_defaults {
java_defaults {
name: "android_stubs_dists_default",
dist: {
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
tag: ".jar",
dest: "android.jar",
},
@@ -411,7 +444,10 @@ java_library_static {
dists: [
{
// Legacy dist path
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
tag: ".jar",
dest: "android_system.jar",
},
@@ -433,14 +469,6 @@ java_library_static {
dist: {
dir: "apistubs/android/test",
},
- dists: [
- {
- // Legacy dist path
- targets: ["sdk", "win_sdk"],
- tag: ".jar",
- dest: "android_test.jar",
- },
- ],
}
java_library_static {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index c3f197853872..11eb5ca7909b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.appsearch;
import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
+import static android.os.Process.INVALID_UID;
import static android.os.UserHandle.USER_NULL;
import android.annotation.ElapsedRealtimeLong;
@@ -36,6 +37,7 @@ import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaResponse;
import android.app.appsearch.StorageInfo;
+import android.app.appsearch.exceptions.AppSearchException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -52,7 +54,6 @@ import android.os.UserManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -122,6 +123,14 @@ public class AppSearchManagerService extends SystemService {
mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null,
/*scheduler=*/ null);
+
+ IntentFilter packageChangedFilter = new IntentFilter();
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ packageChangedFilter.addDataScheme("package");
+ mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL,
+ packageChangedFilter, /*broadcastPermission=*/ null,
+ /*scheduler=*/ null);
}
private class UserActionReceiver extends BroadcastReceiver {
@@ -129,15 +138,15 @@ public class AppSearchManagerService extends SystemService {
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
switch (intent.getAction()) {
case Intent.ACTION_USER_REMOVED:
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
if (userId == USER_NULL) {
- Slog.e(TAG, "userId is missing in the intent: " + intent);
+ Log.e(TAG, "userId is missing in the intent: " + intent);
return;
}
handleUserRemoved(userId);
break;
default:
- Slog.e(TAG, "Received unknown intent: " + intent);
+ Log.e(TAG, "Received unknown intent: " + intent);
}
}
}
@@ -157,9 +166,44 @@ public class AppSearchManagerService extends SystemService {
try {
mImplInstanceManager.removeAppSearchImplForUser(userId);
mLoggerInstanceManager.removePlatformLoggerForUser(userId);
- Slog.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
+ Log.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
} catch (Throwable t) {
- Slog.e(TAG, "Unable to remove data for user: " + userId, t);
+ Log.e(TAG, "Unable to remove data for user: " + userId, t);
+ }
+ }
+
+ private class PackageChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_FULLY_REMOVED:
+ case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ String packageName = intent.getData().getSchemeSpecificPart();
+ if (packageName == null) {
+ Log.e(TAG, "Package name is missing in the intent: " + intent);
+ return;
+ }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
+ if (uid == INVALID_UID) {
+ Log.e(TAG, "uid is missing in the intent: " + intent);
+ return;
+ }
+ handlePackageRemoved(packageName, uid);
+ break;
+ default:
+ Log.e(TAG, "Received unknown intent: " + intent);
+ }
+ }
+ }
+
+ private void handlePackageRemoved(String packageName, int uid) {
+ int userId = UserHandle.getUserId(uid);
+ try {
+ AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext, userId);
+ //TODO(b/145759910) clear visibility setting for package.
+ impl.clearPackageData(packageName);
+ } catch (AppSearchException e) {
+ Log.e(TAG, "Unable to remove data for package: " + packageName, e);
}
}
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index 113f8fe9e248..6dbbcb564b4c 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -26,8 +26,8 @@ import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
+import android.util.IndentingPrintWriter;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
index ca588c509594..09260b775444 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -37,9 +37,9 @@ import android.permission.PermissionManager;
import android.util.ArraySet;
import android.util.Base64;
import android.util.DebugUtils;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index 8b12beb57195..e47715685323 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -15,6 +15,7 @@
*/
package com.android.server.blob;
+import static android.Manifest.permission.ACCESS_BLOBS_ACROSS_USERS;
import static android.app.blob.XmlTags.ATTR_COMMIT_TIME_MS;
import static android.app.blob.XmlTags.ATTR_DESCRIPTION;
import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME;
@@ -36,6 +37,7 @@ import static com.android.server.blob.BlobStoreConfig.TAG;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_COMMIT_TIME;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC;
+import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ALLOW_ACCESS_ACROSS_USERS;
import static com.android.server.blob.BlobStoreConfig.hasLeaseWaitTimeElapsed;
import static com.android.server.blob.BlobStoreUtils.getDescriptionResourceId;
import static com.android.server.blob.BlobStoreUtils.getPackageResources;
@@ -45,15 +47,18 @@ import android.annotation.Nullable;
import android.app.blob.BlobHandle;
import android.app.blob.LeaseInfo;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.ResourceId;
import android.content.res.Resources;
import android.os.ParcelFileDescriptor;
import android.os.RevocableFileDescriptor;
import android.os.UserHandle;
+import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsEvent;
@@ -62,7 +67,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.server.blob.BlobStoreManagerService.DumpArgs;
@@ -85,7 +89,6 @@ class BlobMetadata {
private final long mBlobId;
private final BlobHandle mBlobHandle;
- private final int mUserId;
@GuardedBy("mMetadataLock")
private final ArraySet<Committer> mCommitters = new ArraySet<>();
@@ -94,24 +97,23 @@ class BlobMetadata {
private final ArraySet<Leasee> mLeasees = new ArraySet<>();
/**
- * Contains packageName -> {RevocableFileDescriptors}.
+ * Contains Accessor -> {RevocableFileDescriptors}.
*
* Keep track of RevocableFileDescriptors given to clients which are not yet revoked/closed so
* that when clients access is revoked or the blob gets deleted, we can be sure that clients
* do not have any reference to the blob and the space occupied by the blob can be freed.
*/
@GuardedBy("mRevocableFds")
- private final ArrayMap<String, ArraySet<RevocableFileDescriptor>> mRevocableFds =
+ private final ArrayMap<Accessor, ArraySet<RevocableFileDescriptor>> mRevocableFds =
new ArrayMap<>();
// Do not access this directly, instead use #getBlobFile().
private File mBlobFile;
- BlobMetadata(Context context, long blobId, BlobHandle blobHandle, int userId) {
+ BlobMetadata(Context context, long blobId, BlobHandle blobHandle) {
mContext = context;
this.mBlobId = blobId;
this.mBlobHandle = blobHandle;
- this.mUserId = userId;
}
long getBlobId() {
@@ -122,10 +124,6 @@ class BlobMetadata {
return mBlobHandle;
}
- int getUserId() {
- return mUserId;
- }
-
void addOrReplaceCommitter(@NonNull Committer committer) {
synchronized (mMetadataLock) {
// We need to override the committer data, so first remove any existing
@@ -155,13 +153,24 @@ class BlobMetadata {
}
}
- void removeCommittersFromUnknownPkgs(SparseArray<String> knownPackages) {
+ void removeCommittersFromUnknownPkgs(SparseArray<SparseArray<String>> knownPackages) {
synchronized (mMetadataLock) {
- mCommitters.removeIf(committer ->
- !committer.packageName.equals(knownPackages.get(committer.uid)));
+ mCommitters.removeIf(committer -> {
+ final int userId = UserHandle.getUserId(committer.uid);
+ final SparseArray<String> userPackages = knownPackages.get(userId);
+ if (userPackages == null) {
+ return true;
+ }
+ return !committer.packageName.equals(userPackages.get(committer.uid));
+ });
}
}
+ void addCommittersAndLeasees(BlobMetadata blobMetadata) {
+ mCommitters.addAll(blobMetadata.mCommitters);
+ mLeasees.addAll(blobMetadata.mLeasees);
+ }
+
@Nullable
Committer getExistingCommitter(@NonNull String packageName, int uid) {
synchronized (mCommitters) {
@@ -201,10 +210,16 @@ class BlobMetadata {
}
}
- void removeLeaseesFromUnknownPkgs(SparseArray<String> knownPackages) {
+ void removeLeaseesFromUnknownPkgs(SparseArray<SparseArray<String>> knownPackages) {
synchronized (mMetadataLock) {
- mLeasees.removeIf(leasee ->
- !leasee.packageName.equals(knownPackages.get(leasee.uid)));
+ mLeasees.removeIf(leasee -> {
+ final int userId = UserHandle.getUserId(leasee.uid);
+ final SparseArray<String> userPackages = knownPackages.get(userId);
+ if (userPackages == null) {
+ return true;
+ }
+ return !leasee.packageName.equals(userPackages.get(leasee.uid));
+ });
}
}
@@ -214,6 +229,25 @@ class BlobMetadata {
}
}
+ void removeDataForUser(int userId) {
+ synchronized (mMetadataLock) {
+ mCommitters.removeIf(committer -> (userId == UserHandle.getUserId(committer.uid)));
+ mLeasees.removeIf(leasee -> (userId == UserHandle.getUserId(leasee.uid)));
+ mRevocableFds.entrySet().removeIf(entry -> {
+ final Accessor accessor = entry.getKey();
+ final ArraySet<RevocableFileDescriptor> rFds = entry.getValue();
+ if (userId != UserHandle.getUserId(accessor.uid)) {
+ return false;
+ }
+ for (int i = 0, fdCount = rFds.size(); i < fdCount; ++i) {
+ rFds.valueAt(i).revoke();
+ }
+ rFds.clear();
+ return true;
+ });
+ }
+ }
+
boolean hasValidLeases() {
synchronized (mMetadataLock) {
for (int i = 0, size = mLeasees.size(); i < size; ++i) {
@@ -244,8 +278,12 @@ class BlobMetadata {
}
}
+ final int callingUserId = UserHandle.getUserId(callingUid);
for (int i = 0, size = mCommitters.size(); i < size; ++i) {
final Committer committer = mCommitters.valueAt(i);
+ if (callingUserId != UserHandle.getUserId(committer.uid)) {
+ continue;
+ }
// Check if the caller is the same package that committed the blob.
if (committer.equals(callingPackage, callingUid)) {
@@ -259,38 +297,105 @@ class BlobMetadata {
return true;
}
}
+
+ final boolean canCallerAccessBlobsAcrossUsers = checkCallerCanAccessBlobsAcrossUsers(
+ callingPackage, callingUserId);
+ if (!canCallerAccessBlobsAcrossUsers) {
+ return false;
+ }
+ for (int i = 0, size = mCommitters.size(); i < size; ++i) {
+ final Committer committer = mCommitters.valueAt(i);
+ final int committerUserId = UserHandle.getUserId(committer.uid);
+ if (callingUserId == committerUserId) {
+ continue;
+ }
+ if (!checkCallerCanAccessBlobsAcrossUsers(callingPackage, committerUserId)) {
+ continue;
+ }
+
+ // Check if the caller is allowed access as per the access mode specified
+ // by the committer.
+ if (committer.blobAccessMode.isAccessAllowedForCaller(mContext,
+ callingPackage, committer.packageName, callingUid, attributionTag)) {
+ return true;
+ }
+ }
+
+ }
+ return false;
+ }
+
+ private static boolean checkCallerCanAccessBlobsAcrossUsers(
+ String callingPackage, int callingUserId) {
+ return PermissionManager.checkPackageNamePermission(ACCESS_BLOBS_ACROSS_USERS,
+ callingPackage, callingUserId) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ boolean hasACommitterOrLeaseeInUser(int userId) {
+ return hasACommitterInUser(userId) || hasALeaseeInUser(userId);
+ }
+
+ boolean hasACommitterInUser(int userId) {
+ synchronized (mMetadataLock) {
+ for (int i = 0, size = mCommitters.size(); i < size; ++i) {
+ final Committer committer = mCommitters.valueAt(i);
+ if (userId == UserHandle.getUserId(committer.uid)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean hasALeaseeInUser(int userId) {
+ synchronized (mMetadataLock) {
+ for (int i = 0, size = mLeasees.size(); i < size; ++i) {
+ final Leasee leasee = mLeasees.valueAt(i);
+ if (userId == UserHandle.getUserId(leasee.uid)) {
+ return true;
+ }
+ }
}
return false;
}
boolean isACommitter(@NonNull String packageName, int uid) {
synchronized (mMetadataLock) {
- return isAnAccessor(mCommitters, packageName, uid);
+ return isAnAccessor(mCommitters, packageName, uid, UserHandle.getUserId(uid));
}
}
boolean isALeasee(@Nullable String packageName, int uid) {
synchronized (mMetadataLock) {
- final Leasee leasee = getAccessor(mLeasees, packageName, uid);
+ final Leasee leasee = getAccessor(mLeasees, packageName, uid,
+ UserHandle.getUserId(uid));
+ return leasee != null && leasee.isStillValid();
+ }
+ }
+
+ private boolean isALeaseeInUser(@Nullable String packageName, int uid, int userId) {
+ synchronized (mMetadataLock) {
+ final Leasee leasee = getAccessor(mLeasees, packageName, uid, userId);
return leasee != null && leasee.isStillValid();
}
}
private static <T extends Accessor> boolean isAnAccessor(@NonNull ArraySet<T> accessors,
- @Nullable String packageName, int uid) {
+ @Nullable String packageName, int uid, int userId) {
// Check if the package is an accessor of the data blob.
- return getAccessor(accessors, packageName, uid) != null;
+ return getAccessor(accessors, packageName, uid, userId) != null;
}
private static <T extends Accessor> T getAccessor(@NonNull ArraySet<T> accessors,
- @Nullable String packageName, int uid) {
+ @Nullable String packageName, int uid, int userId) {
// Check if the package is an accessor of the data blob.
for (int i = 0, size = accessors.size(); i < size; ++i) {
final Accessor accessor = accessors.valueAt(i);
if (packageName != null && uid != INVALID_UID
&& accessor.equals(packageName, uid)) {
return (T) accessor;
- } else if (packageName != null && accessor.packageName.equals(packageName)) {
+ } else if (packageName != null && accessor.packageName.equals(packageName)
+ && userId == UserHandle.getUserId(accessor.uid)) {
return (T) accessor;
} else if (uid != INVALID_UID && accessor.uid == uid) {
return (T) accessor;
@@ -299,23 +404,29 @@ class BlobMetadata {
return null;
}
- boolean isALeasee(@NonNull String packageName) {
- return isALeasee(packageName, INVALID_UID);
- }
-
- boolean isALeasee(int uid) {
- return isALeasee(null, uid);
- }
-
- boolean hasOtherLeasees(@NonNull String packageName) {
- return hasOtherLeasees(packageName, INVALID_UID);
+ boolean shouldAttributeToLeasee(@NonNull String packageName, int userId,
+ boolean callerHasStatsPermission) {
+ if (!isALeaseeInUser(packageName, INVALID_UID, userId)) {
+ return false;
+ }
+ if (!callerHasStatsPermission || !hasOtherLeasees(packageName, INVALID_UID, userId)) {
+ return true;
+ }
+ return false;
}
- boolean hasOtherLeasees(int uid) {
- return hasOtherLeasees(null, uid);
+ boolean shouldAttributeToLeasee(int uid, boolean callerHasStatsPermission) {
+ final int userId = UserHandle.getUserId(uid);
+ if (!isALeaseeInUser(null, uid, userId)) {
+ return false;
+ }
+ if (!callerHasStatsPermission || !hasOtherLeasees(null, uid, userId)) {
+ return true;
+ }
+ return false;
}
- private boolean hasOtherLeasees(@Nullable String packageName, int uid) {
+ private boolean hasOtherLeasees(@Nullable String packageName, int uid, int userId) {
synchronized (mMetadataLock) {
for (int i = 0, size = mLeasees.size(); i < size; ++i) {
final Leasee leasee = mLeasees.valueAt(i);
@@ -326,7 +437,8 @@ class BlobMetadata {
if (packageName != null && uid != INVALID_UID
&& !leasee.equals(packageName, uid)) {
return true;
- } else if (packageName != null && !leasee.packageName.equals(packageName)) {
+ } else if (packageName != null && (!leasee.packageName.equals(packageName)
+ || userId != UserHandle.getUserId(leasee.uid))) {
return true;
} else if (uid != INVALID_UID && leasee.uid != uid) {
return true;
@@ -371,7 +483,7 @@ class BlobMetadata {
return mBlobFile;
}
- ParcelFileDescriptor openForRead(String callingPackage) throws IOException {
+ ParcelFileDescriptor openForRead(String callingPackage, int callingUid) throws IOException {
// TODO: Add limit on opened fds
FileDescriptor fd;
try {
@@ -381,7 +493,7 @@ class BlobMetadata {
}
try {
if (BlobStoreConfig.shouldUseRevocableFdForReads()) {
- return createRevocableFd(fd, callingPackage);
+ return createRevocableFd(fd, callingPackage, callingUid);
} else {
return new ParcelFileDescriptor(fd);
}
@@ -393,26 +505,28 @@ class BlobMetadata {
@NonNull
private ParcelFileDescriptor createRevocableFd(FileDescriptor fd,
- String callingPackage) throws IOException {
+ String callingPackage, int callingUid) throws IOException {
final RevocableFileDescriptor revocableFd =
new RevocableFileDescriptor(mContext, fd);
+ final Accessor accessor;
synchronized (mRevocableFds) {
- ArraySet<RevocableFileDescriptor> revocableFdsForPkg =
- mRevocableFds.get(callingPackage);
- if (revocableFdsForPkg == null) {
- revocableFdsForPkg = new ArraySet<>();
- mRevocableFds.put(callingPackage, revocableFdsForPkg);
+ accessor = new Accessor(callingPackage, callingUid);
+ ArraySet<RevocableFileDescriptor> revocableFdsForAccessor =
+ mRevocableFds.get(accessor);
+ if (revocableFdsForAccessor == null) {
+ revocableFdsForAccessor = new ArraySet<>();
+ mRevocableFds.put(accessor, revocableFdsForAccessor);
}
- revocableFdsForPkg.add(revocableFd);
+ revocableFdsForAccessor.add(revocableFd);
}
revocableFd.addOnCloseListener((e) -> {
synchronized (mRevocableFds) {
- final ArraySet<RevocableFileDescriptor> revocableFdsForPkg =
- mRevocableFds.get(callingPackage);
- if (revocableFdsForPkg != null) {
- revocableFdsForPkg.remove(revocableFd);
- if (revocableFdsForPkg.isEmpty()) {
- mRevocableFds.remove(callingPackage);
+ final ArraySet<RevocableFileDescriptor> revocableFdsForAccessor =
+ mRevocableFds.get(accessor);
+ if (revocableFdsForAccessor != null) {
+ revocableFdsForAccessor.remove(revocableFd);
+ if (revocableFdsForAccessor.isEmpty()) {
+ mRevocableFds.remove(accessor);
}
}
}
@@ -421,22 +535,23 @@ class BlobMetadata {
}
void destroy() {
- revokeAllFds();
+ revokeAndClearAllFds();
getBlobFile().delete();
}
- private void revokeAllFds() {
+ private void revokeAndClearAllFds() {
synchronized (mRevocableFds) {
- for (int i = 0, pkgCount = mRevocableFds.size(); i < pkgCount; ++i) {
- final ArraySet<RevocableFileDescriptor> packageFds =
+ for (int i = 0, accessorCount = mRevocableFds.size(); i < accessorCount; ++i) {
+ final ArraySet<RevocableFileDescriptor> rFds =
mRevocableFds.valueAt(i);
- if (packageFds == null) {
+ if (rFds == null) {
continue;
}
- for (int j = 0, fdCount = packageFds.size(); j < fdCount; ++j) {
- packageFds.valueAt(j).revoke();
+ for (int j = 0, fdCount = rFds.size(); j < fdCount; ++j) {
+ rFds.valueAt(j).revoke();
}
}
+ mRevocableFds.clear();
}
}
@@ -547,10 +662,10 @@ class BlobMetadata {
fout.println("<empty>");
} else {
for (int i = 0, count = mRevocableFds.size(); i < count; ++i) {
- final String packageName = mRevocableFds.keyAt(i);
- final ArraySet<RevocableFileDescriptor> packageFds =
+ final Accessor accessor = mRevocableFds.keyAt(i);
+ final ArraySet<RevocableFileDescriptor> rFds =
mRevocableFds.valueAt(i);
- fout.println(packageName + "#" + packageFds.size());
+ fout.println(accessor + ": #" + rFds.size());
}
}
fout.decreaseIndent();
@@ -560,7 +675,6 @@ class BlobMetadata {
void writeToXml(XmlSerializer out) throws IOException {
synchronized (mMetadataLock) {
XmlUtils.writeLongAttribute(out, ATTR_ID, mBlobId);
- XmlUtils.writeIntAttribute(out, ATTR_USER_ID, mUserId);
out.startTag(null, TAG_BLOB_HANDLE);
mBlobHandle.writeToXml(out);
@@ -584,7 +698,9 @@ class BlobMetadata {
static BlobMetadata createFromXml(XmlPullParser in, int version, Context context)
throws XmlPullParserException, IOException {
final long blobId = XmlUtils.readLongAttribute(in, ATTR_ID);
- final int userId = XmlUtils.readIntAttribute(in, ATTR_USER_ID);
+ if (version < XML_VERSION_ALLOW_ACCESS_ACROSS_USERS) {
+ XmlUtils.readIntAttribute(in, ATTR_USER_ID);
+ }
BlobHandle blobHandle = null;
final ArraySet<Committer> committers = new ArraySet<>();
@@ -608,7 +724,7 @@ class BlobMetadata {
return null;
}
- final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle, userId);
+ final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle);
blobMetadata.setCommitters(committers);
blobMetadata.setLeasees(leasees);
return blobMetadata;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index 5cebf8d91cfc..502b29eb1a1f 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -27,12 +27,11 @@ import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.text.TextUtils;
import android.util.DataUnit;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.TimeUtils;
-import com.android.internal.util.IndentingPrintWriter;
-
import java.io.File;
import java.util.concurrent.TimeUnit;
@@ -47,8 +46,9 @@ class BlobStoreConfig {
public static final int XML_VERSION_ADD_DESC_RES_NAME = 3;
public static final int XML_VERSION_ADD_COMMIT_TIME = 4;
public static final int XML_VERSION_ADD_SESSION_CREATION_TIME = 5;
+ public static final int XML_VERSION_ALLOW_ACCESS_ACROSS_USERS = 6;
- public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_SESSION_CREATION_TIME;
+ public static final int XML_VERSION_CURRENT = XML_VERSION_ALLOW_ACCESS_ACROSS_USERS;
public static final long INVALID_BLOB_ID = 0;
public static final long INVALID_BLOB_SIZE = 0;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 0e7354726123..cc5e31a91123 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -32,6 +32,7 @@ import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_ID;
import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE;
import static com.android.server.blob.BlobStoreConfig.LOGV;
import static com.android.server.blob.BlobStoreConfig.TAG;
+import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ALLOW_ACCESS_ACROSS_USERS;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT;
import static com.android.server.blob.BlobStoreConfig.getAdjustedCommitTimeMs;
import static com.android.server.blob.BlobStoreConfig.getDeletionOnLastLeaseDelayMs;
@@ -83,6 +84,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
+import android.util.IndentingPrintWriter;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -96,7 +98,6 @@ import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -129,6 +130,7 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -146,9 +148,9 @@ public class BlobStoreManagerService extends SystemService {
@GuardedBy("mBlobsLock")
private long mCurrentMaxSessionId;
- // Contains data of userId -> {BlobHandle -> {BlobMetadata}}
+ // Contains data of BlobHandle -> BlobMetadata.
@GuardedBy("mBlobsLock")
- private final SparseArray<ArrayMap<BlobHandle, BlobMetadata>> mBlobsMap = new SparseArray<>();
+ private final ArrayMap<BlobHandle, BlobMetadata> mBlobsMap = new ArrayMap<>();
// Contains all ids that are currently in use.
@GuardedBy("mBlobsLock")
@@ -265,27 +267,24 @@ public class BlobStoreManagerService extends SystemService {
return userSessions;
}
- @GuardedBy("mBlobsLock")
- private ArrayMap<BlobHandle, BlobMetadata> getUserBlobsLocked(int userId) {
- ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.get(userId);
- if (userBlobs == null) {
- userBlobs = new ArrayMap<>();
- mBlobsMap.put(userId, userBlobs);
+ @VisibleForTesting
+ void addUserSessionsForTest(LongSparseArray<BlobStoreSession> userSessions, int userId) {
+ synchronized (mBlobsLock) {
+ mSessions.put(userId, userSessions);
}
- return userBlobs;
}
@VisibleForTesting
- void addUserSessionsForTest(LongSparseArray<BlobStoreSession> userSessions, int userId) {
+ BlobMetadata getBlobForTest(BlobHandle blobHandle) {
synchronized (mBlobsLock) {
- mSessions.put(userId, userSessions);
+ return mBlobsMap.get(blobHandle);
}
}
@VisibleForTesting
- void addUserBlobsForTest(ArrayMap<BlobHandle, BlobMetadata> userBlobs, int userId) {
+ int getBlobsCountForTest() {
synchronized (mBlobsLock) {
- mBlobsMap.put(userId, userBlobs);
+ return mBlobsMap.size();
}
}
@@ -319,14 +318,9 @@ public class BlobStoreManagerService extends SystemService {
}
@GuardedBy("mBlobsLock")
- private void addBlobForUserLocked(BlobMetadata blobMetadata, int userId) {
- addBlobForUserLocked(blobMetadata, getUserBlobsLocked(userId));
- }
-
- @GuardedBy("mBlobsLock")
- private void addBlobForUserLocked(BlobMetadata blobMetadata,
- ArrayMap<BlobHandle, BlobMetadata> userBlobs) {
- userBlobs.put(blobMetadata.getBlobHandle(), blobMetadata);
+ @VisibleForTesting
+ void addBlobLocked(BlobMetadata blobMetadata) {
+ mBlobsMap.put(blobMetadata.getBlobHandle(), blobMetadata);
addActiveBlobIdLocked(blobMetadata.getBlobId());
}
@@ -404,8 +398,7 @@ public class BlobStoreManagerService extends SystemService {
private ParcelFileDescriptor openBlobInternal(BlobHandle blobHandle, int callingUid,
String callingPackage, String attributionTag) throws IOException {
synchronized (mBlobsLock) {
- final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
- .get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
if (blobMetadata == null) {
@@ -415,7 +408,7 @@ public class BlobStoreManagerService extends SystemService {
} else {
FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
blobMetadata.getBlobId(), blobMetadata.getSize(),
- FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED);
+ FrameworkStatsLog.BLOB_OPENED__RESULT__ACCESS_NOT_ALLOWED);
}
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
@@ -425,7 +418,7 @@ public class BlobStoreManagerService extends SystemService {
blobMetadata.getBlobId(), blobMetadata.getSize(),
FrameworkStatsLog.BLOB_OPENED__RESULT__SUCCESS);
- return blobMetadata.openForRead(callingPackage);
+ return blobMetadata.openForRead(callingPackage, callingUid);
}
}
@@ -433,11 +426,11 @@ public class BlobStoreManagerService extends SystemService {
private int getCommittedBlobsCountLocked(int uid, String packageName) {
// TODO: Maintain a counter instead of traversing all the blobs
final AtomicInteger blobsCount = new AtomicInteger(0);
- forEachBlobInUser((blobMetadata) -> {
+ forEachBlobLocked(blobMetadata -> {
if (blobMetadata.isACommitter(packageName, uid)) {
blobsCount.getAndIncrement();
}
- }, UserHandle.getUserId(uid));
+ });
return blobsCount.get();
}
@@ -445,11 +438,11 @@ public class BlobStoreManagerService extends SystemService {
private int getLeasedBlobsCountLocked(int uid, String packageName) {
// TODO: Maintain a counter instead of traversing all the blobs
final AtomicInteger blobsCount = new AtomicInteger(0);
- forEachBlobInUser((blobMetadata) -> {
+ forEachBlobLocked(blobMetadata -> {
if (blobMetadata.isALeasee(packageName, uid)) {
blobsCount.getAndIncrement();
}
- }, UserHandle.getUserId(uid));
+ });
return blobsCount.get();
}
@@ -465,8 +458,16 @@ public class BlobStoreManagerService extends SystemService {
throw new LimitExceededException("Too many leased blobs for the caller: "
+ leasesCount);
}
- final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
- .get(blobHandle);
+ if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0
+ && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+ INVALID_BLOB_ID, INVALID_BLOB_SIZE,
+ FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID);
+ throw new IllegalArgumentException(
+ "Lease expiry cannot be later than blobs expiry time");
+ }
+
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
if (blobMetadata == null) {
@@ -481,15 +482,7 @@ public class BlobStoreManagerService extends SystemService {
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
- if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0
- && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
- FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
- blobMetadata.getBlobId(), blobMetadata.getSize(),
- FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID);
- throw new IllegalArgumentException(
- "Lease expiry cannot be later than blobs expiry time");
- }
if (blobMetadata.getSize()
> getRemainingLeaseQuotaBytesInternal(callingUid, callingPackage)) {
@@ -518,20 +511,18 @@ public class BlobStoreManagerService extends SystemService {
@GuardedBy("mBlobsLock")
long getTotalUsageBytesLocked(int callingUid, String callingPackage) {
final AtomicLong totalBytes = new AtomicLong(0);
- forEachBlobInUser((blobMetadata) -> {
+ forEachBlobLocked((blobMetadata) -> {
if (blobMetadata.isALeasee(callingPackage, callingUid)) {
totalBytes.getAndAdd(blobMetadata.getSize());
}
- }, UserHandle.getUserId(callingUid));
+ });
return totalBytes.get();
}
private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid,
String callingPackage, String attributionTag) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
- getUserBlobsLocked(UserHandle.getUserId(callingUid));
- final BlobMetadata blobMetadata = userBlobs.get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
throw new SecurityException("Caller not allowed to access " + blobHandle
@@ -547,12 +538,12 @@ public class BlobStoreManagerService extends SystemService {
synchronized (mBlobsLock) {
// Check if blobMetadata object is still valid. If it is not, then
// it means that it was already deleted and nothing else to do here.
- if (!Objects.equals(userBlobs.get(blobHandle), blobMetadata)) {
+ if (!Objects.equals(mBlobsMap.get(blobHandle), blobMetadata)) {
return;
}
if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
deleteBlobLocked(blobMetadata);
- userBlobs.remove(blobHandle);
+ mBlobsMap.remove(blobHandle);
}
writeBlobsInfoAsync();
}
@@ -583,12 +574,18 @@ public class BlobStoreManagerService extends SystemService {
}
return packageResources;
};
- getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> {
+ forEachBlobLocked((blobHandle, blobMetadata) -> {
+ if (!blobMetadata.hasACommitterOrLeaseeInUser(userId)) {
+ return;
+ }
final ArrayList<LeaseInfo> leaseInfos = new ArrayList<>();
blobMetadata.forEachLeasee(leasee -> {
if (!leasee.isStillValid()) {
return;
}
+ if (userId != UserHandle.getUserId(leasee.uid)) {
+ return;
+ }
final int descriptionResId = leasee.descriptionResEntryName == null
? Resources.ID_NULL
: getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
@@ -608,9 +605,7 @@ public class BlobStoreManagerService extends SystemService {
private void deleteBlobInternal(long blobId, int callingUid) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(
- UserHandle.getUserId(callingUid));
- userBlobs.entrySet().removeIf(entry -> {
+ mBlobsMap.entrySet().removeIf(entry -> {
final BlobMetadata blobMetadata = entry.getValue();
if (blobMetadata.getBlobId() == blobId) {
deleteBlobLocked(blobMetadata);
@@ -625,19 +620,20 @@ public class BlobStoreManagerService extends SystemService {
private List<BlobHandle> getLeasedBlobsInternal(int callingUid,
@NonNull String callingPackage) {
final ArrayList<BlobHandle> leasedBlobs = new ArrayList<>();
- forEachBlobInUser(blobMetadata -> {
- if (blobMetadata.isALeasee(callingPackage, callingUid)) {
- leasedBlobs.add(blobMetadata.getBlobHandle());
- }
- }, UserHandle.getUserId(callingUid));
+ synchronized (mBlobsLock) {
+ forEachBlobLocked(blobMetadata -> {
+ if (blobMetadata.isALeasee(callingPackage, callingUid)) {
+ leasedBlobs.add(blobMetadata.getBlobHandle());
+ }
+ });
+ }
return leasedBlobs;
}
private LeaseInfo getLeaseInfoInternal(BlobHandle blobHandle,
int callingUid, @NonNull String callingPackage, String attributionTag) {
synchronized (mBlobsLock) {
- final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
- .get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
throw new SecurityException("Caller not allowed to access " + blobHandle
@@ -699,14 +695,14 @@ public class BlobStoreManagerService extends SystemService {
FrameworkStatsLog.BLOB_COMMITTED__RESULT__COUNT_LIMIT_EXCEEDED);
break;
}
- final int userId = UserHandle.getUserId(session.getOwnerUid());
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(
- userId);
- BlobMetadata blob = userBlobs.get(session.getBlobHandle());
- if (blob == null) {
+ final BlobMetadata blob;
+ final int blobIndex = mBlobsMap.indexOfKey(session.getBlobHandle());
+ if (blobIndex >= 0) {
+ blob = mBlobsMap.valueAt(blobIndex);
+ } else {
blob = new BlobMetadata(mContext, session.getSessionId(),
- session.getBlobHandle(), userId);
- addBlobForUserLocked(blob, userBlobs);
+ session.getBlobHandle());
+ addBlobLocked(blob);
}
final Committer existingCommitter = blob.getExistingCommitter(
session.getOwnerPackageName(), session.getOwnerUid());
@@ -738,7 +734,7 @@ public class BlobStoreManagerService extends SystemService {
// But if it is a recommit, just leave it as is.
if (session.getSessionId() == blob.getBlobId()) {
deleteBlobLocked(blob);
- userBlobs.remove(blob.getBlobHandle());
+ mBlobsMap.remove(blob.getBlobHandle());
}
}
// Delete redundant data from recommits.
@@ -874,13 +870,10 @@ public class BlobStoreManagerService extends SystemService {
out.startTag(null, TAG_BLOBS);
XmlUtils.writeIntAttribute(out, ATTR_VERSION, XML_VERSION_CURRENT);
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- out.startTag(null, TAG_BLOB);
- userBlobs.valueAt(j).writeToXml(out);
- out.endTag(null, TAG_BLOB);
- }
+ for (int i = 0, count = mBlobsMap.size(); i < count; ++i) {
+ out.startTag(null, TAG_BLOB);
+ mBlobsMap.valueAt(i).writeToXml(out);
+ out.endTag(null, TAG_BLOB);
}
out.endTag(null, TAG_BLOBS);
@@ -925,16 +918,21 @@ public class BlobStoreManagerService extends SystemService {
if (TAG_BLOB.equals(in.getName())) {
final BlobMetadata blobMetadata = BlobMetadata.createFromXml(
in, version, mContext);
- final SparseArray<String> userPackages = allPackages.get(
- blobMetadata.getUserId());
- if (userPackages == null) {
- blobMetadata.getBlobFile().delete();
+ blobMetadata.removeCommittersFromUnknownPkgs(allPackages);
+ blobMetadata.removeLeaseesFromUnknownPkgs(allPackages);
+ mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, blobMetadata.getBlobId());
+ if (version >= XML_VERSION_ALLOW_ACCESS_ACROSS_USERS) {
+ addBlobLocked(blobMetadata);
} else {
- addBlobForUserLocked(blobMetadata, blobMetadata.getUserId());
- blobMetadata.removeCommittersFromUnknownPkgs(userPackages);
- blobMetadata.removeLeaseesFromUnknownPkgs(userPackages);
+ final BlobMetadata existingBlobMetadata = mBlobsMap.get(
+ blobMetadata.getBlobHandle());
+ if (existingBlobMetadata == null) {
+ addBlobLocked(blobMetadata);
+ } else {
+ existingBlobMetadata.addCommittersAndLeasees(blobMetadata);
+ blobMetadata.getBlobFile().delete();
+ }
}
- mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, blobMetadata.getBlobId());
}
}
if (LOGV) {
@@ -977,14 +975,6 @@ public class BlobStoreManagerService extends SystemService {
}
}
- private int getPackageUid(String packageName, int userId) {
- final int uid = mPackageManagerInternal.getPackageUid(
- packageName,
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES,
- userId);
- return uid;
- }
-
private SparseArray<SparseArray<String>> getAllPackages() {
final SparseArray<SparseArray<String>> allPackages = new SparseArray<>();
final int[] allUsers = LocalServices.getService(UserManagerInternal.class).getUserIds();
@@ -1004,7 +994,7 @@ public class BlobStoreManagerService extends SystemService {
return allPackages;
}
- AtomicFile prepareSessionsIndexFile() {
+ private AtomicFile prepareSessionsIndexFile() {
final File file = BlobStoreConfig.prepareSessionIndexFile();
if (file == null) {
return null;
@@ -1012,7 +1002,7 @@ public class BlobStoreManagerService extends SystemService {
return new AtomicFile(file, "session_index" /* commitLogTag */);
}
- AtomicFile prepareBlobsIndexFile() {
+ private AtomicFile prepareBlobsIndexFile() {
final File file = BlobStoreConfig.prepareBlobsIndexFile();
if (file == null) {
return null;
@@ -1037,9 +1027,7 @@ public class BlobStoreManagerService extends SystemService {
writeBlobSessionsAsync();
// Remove the package from the committer and leasee list
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
- getUserBlobsLocked(UserHandle.getUserId(uid));
- userBlobs.entrySet().removeIf(entry -> {
+ mBlobsMap.entrySet().removeIf(entry -> {
final BlobMetadata blobMetadata = entry.getValue();
final boolean isACommitter = blobMetadata.isACommitter(packageName, uid);
if (isACommitter) {
@@ -1074,14 +1062,15 @@ public class BlobStoreManagerService extends SystemService {
}
}
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
- mBlobsMap.removeReturnOld(userId);
- if (userBlobs != null) {
- for (int i = 0, count = userBlobs.size(); i < count; ++i) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(i);
+ mBlobsMap.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
+ blobMetadata.removeDataForUser(userId);
+ if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
deleteBlobLocked(blobMetadata);
+ return true;
}
- }
+ return false;
+ });
if (LOGV) {
Slog.v(TAG, "Removed blobs data in user " + userId);
}
@@ -1114,22 +1103,19 @@ public class BlobStoreManagerService extends SystemService {
}
// Cleanup any stale blobs.
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- userBlobs.entrySet().removeIf(entry -> {
- final BlobMetadata blobMetadata = entry.getValue();
+ mBlobsMap.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
- // Remove expired leases
- blobMetadata.removeExpiredLeases();
+ // Remove expired leases
+ blobMetadata.removeExpiredLeases();
- if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
- deleteBlobLocked(blobMetadata);
- deletedBlobIds.add(blobMetadata.getBlobId());
- return true;
- }
- return false;
- });
- }
+ if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
+ deleteBlobLocked(blobMetadata);
+ deletedBlobIds.add(blobMetadata.getBlobId());
+ return true;
+ }
+ return false;
+ });
writeBlobsInfoAsync();
// Cleanup any stale sessions.
@@ -1195,34 +1181,34 @@ public class BlobStoreManagerService extends SystemService {
void runClearAllBlobs(@UserIdInt int userId) {
synchronized (mBlobsLock) {
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final int blobUserId = mBlobsMap.keyAt(i);
- if (userId != UserHandle.USER_ALL && userId != blobUserId) {
- continue;
+ mBlobsMap.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
+ if (userId == UserHandle.USER_ALL) {
+ mActiveBlobIds.remove(blobMetadata.getBlobId());
+ return true;
}
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- mActiveBlobIds.remove(userBlobs.valueAt(j).getBlobId());
+ blobMetadata.removeDataForUser(userId);
+ if (blobMetadata.shouldBeDeleted(false /* respectLeaseWaitTime */)) {
+ mActiveBlobIds.remove(blobMetadata.getBlobId());
+ return true;
}
- }
- if (userId == UserHandle.USER_ALL) {
- mBlobsMap.clear();
- } else {
- mBlobsMap.remove(userId);
- }
+ return false;
+ });
writeBlobsInfoAsync();
}
}
void deleteBlob(@NonNull BlobHandle blobHandle, @UserIdInt int userId) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- final BlobMetadata blobMetadata = userBlobs.get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null) {
return;
}
- deleteBlobLocked(blobMetadata);
- userBlobs.remove(blobHandle);
+ blobMetadata.removeDataForUser(userId);
+ if (blobMetadata.shouldBeDeleted(false /* respectLeaseWaitTime */)) {
+ deleteBlobLocked(blobMetadata);
+ mBlobsMap.remove(blobHandle);
+ }
writeBlobsInfoAsync();
}
}
@@ -1235,11 +1221,12 @@ public class BlobStoreManagerService extends SystemService {
boolean isBlobAvailable(long blobId, int userId) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- for (BlobMetadata blobMetadata : userBlobs.values()) {
- if (blobMetadata.getBlobId() == blobId) {
- return true;
+ for (int i = 0, blobCount = mBlobsMap.size(); i < blobCount; ++i) {
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(i);
+ if (blobMetadata.getBlobId() != blobId) {
+ continue;
}
+ return blobMetadata.hasACommitterInUser(userId);
}
return false;
}
@@ -1274,27 +1261,22 @@ public class BlobStoreManagerService extends SystemService {
@GuardedBy("mBlobsLock")
private void dumpBlobsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final int userId = mBlobsMap.keyAt(i);
- if (!dumpArgs.shouldDumpUser(userId)) {
+ fout.println("List of blobs (" + mBlobsMap.size() + "):");
+ fout.increaseIndent();
+ for (int i = 0, blobCount = mBlobsMap.size(); i < blobCount; ++i) {
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(i);
+ if (!dumpArgs.shouldDumpBlob(blobMetadata.getBlobId())) {
continue;
}
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- fout.println("List of blobs in user #"
- + userId + " (" + userBlobs.size() + "):");
+ fout.println("Blob #" + blobMetadata.getBlobId());
fout.increaseIndent();
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(j);
- if (!dumpArgs.shouldDumpBlob(blobMetadata.getBlobId())) {
- continue;
- }
- fout.println("Blob #" + blobMetadata.getBlobId());
- fout.increaseIndent();
- blobMetadata.dump(fout, dumpArgs);
- fout.decreaseIndent();
- }
+ blobMetadata.dump(fout, dumpArgs);
fout.decreaseIndent();
}
+ if (mBlobsMap.isEmpty()) {
+ fout.println("<empty>");
+ }
+ fout.decreaseIndent();
}
private class BlobStorageStatsAugmenter implements StorageStatsAugmenter {
@@ -1308,13 +1290,12 @@ public class BlobStoreManagerService extends SystemService {
}
}, userId);
- forEachBlobInUser(blobMetadata -> {
- if (blobMetadata.isALeasee(packageName)) {
- if (!blobMetadata.hasOtherLeasees(packageName) || !callerHasStatsPermission) {
- blobsDataSize.getAndAdd(blobMetadata.getSize());
- }
+ forEachBlob(blobMetadata -> {
+ if (blobMetadata.shouldAttributeToLeasee(packageName, userId,
+ callerHasStatsPermission)) {
+ blobsDataSize.getAndAdd(blobMetadata.getSize());
}
- }, userId);
+ });
stats.dataSize += blobsDataSize.get();
}
@@ -1330,13 +1311,12 @@ public class BlobStoreManagerService extends SystemService {
}
}, userId);
- forEachBlobInUser(blobMetadata -> {
- if (blobMetadata.isALeasee(uid)) {
- if (!blobMetadata.hasOtherLeasees(uid) || !callerHasStatsPermission) {
- blobsDataSize.getAndAdd(blobMetadata.getSize());
- }
+ forEachBlob(blobMetadata -> {
+ if (blobMetadata.shouldAttributeToLeasee(uid,
+ callerHasStatsPermission)) {
+ blobsDataSize.getAndAdd(blobMetadata.getSize());
}
- }, userId);
+ });
stats.dataSize += blobsDataSize.get();
}
@@ -1352,13 +1332,26 @@ public class BlobStoreManagerService extends SystemService {
}
}
- private void forEachBlobInUser(Consumer<BlobMetadata> consumer, int userId) {
- synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- for (int i = 0, count = userBlobs.size(); i < count; ++i) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(i);
- consumer.accept(blobMetadata);
- }
+ private void forEachBlob(Consumer<BlobMetadata> consumer) {
+ synchronized (mBlobsMap) {
+ forEachBlobLocked(consumer);
+ }
+ }
+
+ @GuardedBy("mBlobsMap")
+ private void forEachBlobLocked(Consumer<BlobMetadata> consumer) {
+ for (int blobIdx = 0, count = mBlobsMap.size(); blobIdx < count; ++blobIdx) {
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(blobIdx);
+ consumer.accept(blobMetadata);
+ }
+ }
+
+ @GuardedBy("mBlobsMap")
+ private void forEachBlobLocked(BiConsumer<BlobHandle, BlobMetadata> consumer) {
+ for (int blobIdx = 0, count = mBlobsMap.size(); blobIdx < count; ++blobIdx) {
+ final BlobHandle blobHandle = mBlobsMap.keyAt(blobIdx);
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(blobIdx);
+ consumer.accept(blobHandle, blobMetadata);
}
}
@@ -1886,15 +1879,7 @@ public class BlobStoreManagerService extends SystemService {
}
private int pullBlobData(int atomTag, List<StatsEvent> data) {
- synchronized (mBlobsLock) {
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- final BlobMetadata blob = userBlobs.valueAt(j);
- data.add(blob.dumpAsStatsEvent(atomTag));
- }
- }
- }
+ forEachBlob(blobMetadata -> data.add(blobMetadata.dumpAsStatsEvent(atomTag)));
return StatsManager.PULL_SUCCESS;
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 2c3f682a46e0..3f0032fe537e 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -56,12 +56,12 @@ import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ExceptionUtils;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.blob.BlobStoreManagerService.DumpArgs;
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 88f3df8fa2c4..9ea6f7946fcf 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -208,10 +208,10 @@ public class AlarmManager {
public static final int FLAG_PRIORITIZE = 1 << 6;
/**
- * For apps targeting {@link Build.VERSION_CODES#S} or above, APIs
- * {@link #setExactAndAllowWhileIdle(int, long, PendingIntent)} and
- * {@link #setAlarmClock(AlarmClockInfo, PendingIntent)} will require holding a new
- * permission {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}
+ * For apps targeting {@link Build.VERSION_CODES#S} or above, any APIs setting exact alarms,
+ * e.g. {@link #setExact(int, long, PendingIntent)},
+ * {@link #setAlarmClock(AlarmClockInfo, PendingIntent)} and others will require holding a new
+ * permission {@link Manifest.permission#SCHEDULE_EXACT_ALARM}
*
* @hide
*/
@@ -219,6 +219,21 @@ public class AlarmManager {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
public static final long REQUIRE_EXACT_ALARM_PERMISSION = 171306433L;
+ /**
+ * For apps targeting {@link Build.VERSION_CODES#S} or above, all inexact alarms will require
+ * to have a minimum window size, expected to be on the order of a few minutes.
+ *
+ * Practically, any alarms requiring smaller windows are the same as exact alarms and should use
+ * the corresponding APIs provided, like {@link #setExact(int, long, PendingIntent)}, et al.
+ *
+ * Inexact alarm with shorter windows specified will have their windows elongated by the system.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ public static final long ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS = 185199076L;
+
@UnsupportedAppUsage
private final IAlarmManager mService;
private final Context mContext;
@@ -483,6 +498,11 @@ public class AlarmManager {
* modest timeliness requirements for its alarms.
*
* <p>
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, the system will ensure that the window
+ * specified is at least a few minutes, as smaller windows are considered practically exact
+ * and should use the other APIs provided for exact alarms.
+ *
+ * <p>
* This method can also be used to achieve strict ordering guarantees among
* multiple alarms by ensuring that the windows requested for each alarm do
* not intersect.
@@ -532,6 +552,13 @@ public class AlarmManager {
* The OnAlarmListener {@link OnAlarmListener#onAlarm() onAlarm()} method will be
* invoked via the specified target Handler, or on the application's main looper
* if {@code null} is passed as the {@code targetHandler} parameter.
+ *
+ * <p>
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, the system will ensure that the window
+ * specified is at least a few minutes, as smaller windows are considered practically exact
+ * and should use the other APIs provided for exact alarms.
+ *
+ * @see #setWindow(int, long, long, PendingIntent)
*/
public void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
String tag, OnAlarmListener listener, Handler targetHandler) {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 7a3614172dff..31da2017bdef 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -452,7 +452,8 @@ public class AlarmManagerService extends SystemService {
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * INTERVAL_DAY;
- private static final long DEFAULT_MIN_WINDOW = 10_000;
+ // TODO (b/185199076): Tune based on breakage reports.
+ private static final long DEFAULT_MIN_WINDOW = 30 * 60 * 1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10 * 1000;
private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
@@ -1688,12 +1689,22 @@ public class AlarmManagerService extends SystemService {
windowLength = AlarmManager.WINDOW_EXACT;
}
- // Sanity check the window length. This will catch people mistakenly
- // trying to pass an end-of-window timestamp rather than a duration.
- if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
+ // Snap the window to reasonable limits.
+ if (windowLength > INTERVAL_DAY) {
Slog.w(TAG, "Window length " + windowLength
- + "ms suspiciously long; limiting to 1 hour");
- windowLength = AlarmManager.INTERVAL_HOUR;
+ + "ms suspiciously long; limiting to 1 day");
+ windowLength = INTERVAL_DAY;
+ } else if (windowLength > 0 && windowLength < mConstants.MIN_WINDOW) {
+ if (CompatChanges.isChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS,
+ callingPackage, UserHandle.getUserHandleForUid(callingUid))) {
+ Slog.w(TAG, "Window length " + windowLength + "ms too short; expanding to "
+ + mConstants.MIN_WINDOW + "ms.");
+ windowLength = mConstants.MIN_WINDOW;
+ } else {
+ // TODO (b/185199076): Remove log once we have some data about what apps will break
+ Slog.wtf(TAG, "Short window " + windowLength + "ms specified by "
+ + callingPackage);
+ }
}
// Sanity check the recurrence interval. This will catch people who supply
@@ -1737,7 +1748,6 @@ public class AlarmManagerService extends SystemService {
// Fix this window in place, so that as time approaches we don't collapse it.
windowLength = maxElapsed - triggerElapsed;
} else {
- windowLength = Math.max(windowLength, mConstants.MIN_WINDOW);
maxElapsed = triggerElapsed + windowLength;
}
synchronized (mLock) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 90ece0ba7c61..500735b0b299 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -83,6 +83,7 @@ public final class ConnectivityController extends RestrictingController implemen
* instance.
*/
private static final long MIN_STATS_UPDATE_INTERVAL_MS = 30_000L;
+ private static final long MIN_ADJUST_CALLBACK_INTERVAL_MS = 1_000L;
private static final int UNBYPASSABLE_BG_BLOCKED_REASONS =
~ConnectivityManager.BLOCKED_REASON_NONE;
@@ -210,6 +211,7 @@ public final class ConnectivityController extends RestrictingController implemen
* is only done in {@link #maybeAdjustRegisteredCallbacksLocked()} and may sometimes be stale.
*/
private final List<UidStats> mSortedStats = new ArrayList<>();
+ private long mLastCallbackAdjustmentTimeElapsed;
private static final int MSG_ADJUST_CALLBACKS = 0;
@@ -693,7 +695,11 @@ public final class ConnectivityController extends RestrictingController implemen
}
private void postAdjustCallbacks() {
- mHandler.obtainMessage(MSG_ADJUST_CALLBACKS).sendToTarget();
+ postAdjustCallbacks(0);
+ }
+
+ private void postAdjustCallbacks(long delayMs) {
+ mHandler.sendEmptyMessageDelayed(MSG_ADJUST_CALLBACKS, delayMs);
}
@GuardedBy("mLock")
@@ -708,6 +714,12 @@ public final class ConnectivityController extends RestrictingController implemen
}
final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (nowElapsed - mLastCallbackAdjustmentTimeElapsed < MIN_ADJUST_CALLBACK_INTERVAL_MS) {
+ postAdjustCallbacks(MIN_ADJUST_CALLBACK_INTERVAL_MS);
+ return;
+ }
+
+ mLastCallbackAdjustmentTimeElapsed = nowElapsed;
mSortedStats.clear();
for (int u = 0; u < mUidStats.size(); ++u) {
@@ -729,17 +741,23 @@ public final class ConnectivityController extends RestrictingController implemen
for (int j = 0; j < jobs.size(); ++j) {
JobStatus job = jobs.valueAt(j);
- us.earliestEnqueueTime = Math.min(us.earliestEnqueueTime, job.enqueueTime);
if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_CONNECTIVITY)) {
us.numReadyWithConnectivity++;
if (isNetworkAvailable(job)) {
us.numRequestedNetworkAvailable++;
}
+ // Only use the enqueue time of jobs that would be ready to prevent apps
+ // from gaming the system (eg. by scheduling a job that requires all
+ // constraints and has a minimum latency of 6 months to always have the
+ // earliest enqueue time).
+ us.earliestEnqueueTime = Math.min(us.earliestEnqueueTime, job.enqueueTime);
+ if (job.shouldTreatAsExpeditedJob() || job.startedAsExpeditedJob) {
+ us.earliestEJEnqueueTime =
+ Math.min(us.earliestEJEnqueueTime, job.enqueueTime);
+ }
}
if (job.shouldTreatAsExpeditedJob() || job.startedAsExpeditedJob) {
us.numEJs++;
- us.earliestEJEnqueueTime =
- Math.min(us.earliestEJEnqueueTime, job.enqueueTime);
} else {
us.numRegular++;
}
@@ -920,7 +938,10 @@ public final class ConnectivityController extends RestrictingController implemen
UidDefaultNetworkCallback defaultNetworkCallback =
mCurrentDefaultNetworkCallbacks.get(jobs.valueAt(0).getSourceUid());
if (defaultNetworkCallback == null) {
- maybeRegisterDefaultNetworkCallbackLocked(jobs.valueAt(0));
+ // This method is only called via a network callback object. That means something
+ // changed about a general network characteristic (since we wouldn't be in this
+ // situation if called from a UID_specific callback). The general network callback
+ // will handle adjusting the per-UID callbacks, so nothing left to do here.
return false;
}
@@ -1100,8 +1121,13 @@ public final class ConnectivityController extends RestrictingController implemen
synchronized (mLock) {
if (Objects.equals(mDefaultNetwork, network)) {
mDefaultNetwork = null;
+ updateTrackedJobsLocked(mUid, network);
+ // Add a delay in case onAvailable()+onBlockedStatusChanged is called for a
+ // new network. If this onLost was called because the network is completely
+ // gone, the delay will hel make sure we don't have a short burst of adjusting
+ // callback calls.
+ postAdjustCallbacks(1000);
}
- updateTrackedJobsLocked(mUid, network);
}
}
diff --git a/boot/hiddenapi/OWNERS b/boot/hiddenapi/OWNERS
index 5d869fc12ebd..74a3dc05f0da 100644
--- a/boot/hiddenapi/OWNERS
+++ b/boot/hiddenapi/OWNERS
@@ -1,7 +1,5 @@
# compat-team@ for changes to hiddenapi files
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+file:tools/platform-compat:/OWNERS
# Escalations:
per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index 6823f65dd624..4b12d54c5a57 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5666,6 +5666,7 @@ package android.app {
field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
field public static final String EXTRA_CALL_PERSON = "android.callPerson";
field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
@@ -5972,6 +5973,7 @@ package android.app {
method @NonNull public static android.app.Notification.CallStyle forScreeningCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent, @NonNull android.app.PendingIntent);
method @NonNull public android.app.Notification.CallStyle setAnswerButtonColorHint(@ColorInt int);
method @NonNull public android.app.Notification.CallStyle setDeclineButtonColorHint(@ColorInt int);
+ method @NonNull public android.app.Notification.CallStyle setIsVideo(boolean);
method @NonNull public android.app.Notification.CallStyle setVerificationIcon(@Nullable android.graphics.drawable.Icon);
method @NonNull public android.app.Notification.CallStyle setVerificationText(@Nullable CharSequence);
}
@@ -7130,7 +7132,7 @@ package android.app.admin {
method public int getGlobalPrivateDnsMode(@NonNull android.content.ComponentName);
method @NonNull public java.util.List<byte[]> getInstalledCaCerts(@Nullable android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getKeepUninstalledPackages(@Nullable android.content.ComponentName);
- method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getKeyPairGrants(@NonNull String);
+ method @NonNull public java.util.Map<java.lang.Integer,java.util.Set<java.lang.String>> getKeyPairGrants(@NonNull String);
method public int getKeyguardDisabledFeatures(@Nullable android.content.ComponentName);
method public int getLockTaskFeatures(@NonNull android.content.ComponentName);
method @NonNull public String[] getLockTaskPackages(@NonNull android.content.ComponentName);
@@ -11089,7 +11091,6 @@ package android.content {
field public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
field public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
- field public static final String ACTION_PACKAGE_FULLY_LOADED = "android.intent.action.PACKAGE_FULLY_LOADED";
field public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field @Deprecated public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
field public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
@@ -25216,6 +25217,7 @@ package android.media.session {
method public float getPlaybackSpeed();
method public long getPosition();
method public int getState();
+ method public boolean isActive();
method public void writeToParcel(android.os.Parcel, int);
field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
field public static final long ACTION_PAUSE = 2L; // 0x2L
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b1e448b7dd77..2be8c9aadcc6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -161,10 +161,6 @@ package android.media.session {
method public void onVolumeChanged(@NonNull android.media.session.MediaSession.Token, int);
}
- public final class PlaybackState implements android.os.Parcelable {
- method public boolean isActiveState();
- }
-
}
package android.net {
@@ -236,7 +232,7 @@ package android.net {
}
public class VpnManager {
- field @Deprecated public static final int TYPE_VPN_LEGACY = 3; // 0x3
+ field public static final int TYPE_VPN_LEGACY = 3; // 0x3
field public static final int TYPE_VPN_NONE = -1; // 0xffffffff
field public static final int TYPE_VPN_OEM = 4; // 0x4
field public static final int TYPE_VPN_PLATFORM = 2; // 0x2
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ce408d1a80f1..199d77a232e9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -962,6 +962,9 @@ package android.app.admin {
field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+ field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
+ field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
+ field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4
field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
@@ -976,10 +979,6 @@ package android.app.admin {
field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
field public static final int STATE_USER_UNMANAGED = 0; // 0x0
- field public static final int SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
- field public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3; // 0x3
- field public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
- field public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
}
public final class SystemUpdatePolicy implements android.os.Parcelable {
@@ -1949,6 +1948,8 @@ package android.bluetooth {
}
public static interface BluetoothAdapter.OobDataCallback {
+ method public void onError(int);
+ method public void onOobData(int, @Nullable android.bluetooth.OobData);
}
public final class BluetoothDevice implements android.os.Parcelable {
@@ -8967,7 +8968,7 @@ package android.printservice.recommendation {
package android.provider {
public class CallLog {
- method @RequiresPermission(allOf={android.Manifest.permission.WRITE_CALL_LOG, android.Manifest.permission.INTERACT_ACROSS_USERS}) public static void storeCallComposerPictureAsUser(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull java.io.InputStream, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.net.Uri,android.provider.CallLog.CallComposerLoggingException>);
+ method @RequiresPermission(allOf={android.Manifest.permission.WRITE_CALL_LOG, android.Manifest.permission.INTERACT_ACROSS_USERS}) public static void storeCallComposerPicture(@NonNull android.content.Context, @NonNull java.io.InputStream, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.net.Uri,android.provider.CallLog.CallComposerLoggingException>);
}
public static class CallLog.CallComposerLoggingException extends java.lang.Throwable {
@@ -13627,7 +13628,6 @@ package android.telephony.ims {
method public int describeContents();
method @Nullable public String getCallIdParameter();
method @NonNull public byte[] getContent();
- method @Deprecated @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
method @NonNull public String getViaBranchParameter();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d59e4f8e9c05..0541934fd665 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -263,10 +263,12 @@ package android.app {
public class BroadcastOptions {
ctor public BroadcastOptions(@NonNull android.os.Bundle);
+ method public int getMaxManifestReceiverApiLevel();
method public long getTemporaryAppAllowlistDuration();
method @Nullable public String getTemporaryAppAllowlistReason();
method public int getTemporaryAppAllowlistReasonCode();
method public int getTemporaryAppAllowlistType();
+ method public void setMaxManifestReceiverApiLevel(int);
}
public class DownloadManager {
@@ -3170,5 +3172,12 @@ package android.window {
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction);
}
+ @UiContext public abstract class WindowProviderService extends android.app.Service {
+ ctor public WindowProviderService();
+ method public final void attachToWindowToken(@NonNull android.os.IBinder);
+ method @Nullable public android.os.Bundle getWindowContextOptions();
+ method public abstract int getWindowType();
+ }
+
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index db42803ac9f9..a24555f79a1c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4272,7 +4272,8 @@ public class ActivityManager {
try {
getService().broadcastIntentWithFeature(
null, null, intent, null, null, Activity.RESULT_OK, null, null,
- null /*permission*/, appOp, null, false, true, userId);
+ null /*requiredPermissions*/, null /*excludedPermissions*/, appOp, null, false,
+ true, userId);
} catch (RemoteException ex) {
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8ff14b0ad28f..98fee9cf90cf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4390,11 +4390,12 @@ public final class ActivityThread extends ClientTransactionHandler
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
- ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
+ final ContextImpl context = ContextImpl.getImpl(service
+ .createServiceBaseContext(this, packageInfo));
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 9da2581e449f..bd7162c1bf3b 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -250,6 +250,7 @@ public class BroadcastOptions {
* them. This only applies to receivers declared in the app's AndroidManifest.xml.
* @hide
*/
+ @TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void setMaxManifestReceiverApiLevel(int apiLevel) {
mMaxManifestReceiverApiLevel = apiLevel;
@@ -259,6 +260,7 @@ public class BroadcastOptions {
* Return {@link #setMaxManifestReceiverApiLevel}.
* @hide
*/
+ @TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public int getMaxManifestReceiverApiLevel() {
return mMaxManifestReceiverApiLevel;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f7ea3815d567..9753b6748c78 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1176,8 +1176,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- false, getUserId());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1194,7 +1194,8 @@ class ContextImpl extends Context {
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1209,7 +1210,8 @@ class ContextImpl extends Context {
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1224,7 +1226,24 @@ class ContextImpl extends Context {
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
+ String[] excludedPermissions) {
+ warnIfCallingFromSystemProcess();
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ intent.prepareToLeaveProcess(this);
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions, excludedPermissions,
+ AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1241,7 +1260,8 @@ class ContextImpl extends Context {
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, options, false, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1257,8 +1277,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
- false, getUserId());
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1275,7 +1295,8 @@ class ContextImpl extends Context {
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, true, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1337,8 +1358,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
- options, true, false, getUserId());
+ rd, initialCode, initialData, initialExtras, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, options, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1351,8 +1372,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- false, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1375,7 +1396,8 @@ class ContextImpl extends Context {
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, options, false, false, user.getIdentifier());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1391,8 +1413,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
- false, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1442,8 +1464,9 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
- options, true, false, user.getIdentifier());
+ rd, initialCode, initialData, initialExtras, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, options, true, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1483,8 +1506,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- true, getUserId());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1522,8 +1545,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
- false, true, getUserId());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, options, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1558,8 +1581,9 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
- true, true, getUserId());
+ rd, initialCode, initialData, initialExtras, null,
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1590,8 +1614,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- true, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1605,8 +1629,8 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
- false, true, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1640,8 +1664,9 @@ class ContextImpl extends Context {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
- true, true, user.getIdentifier());
+ rd, initialCode, initialData, initialExtras, null,
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f9279da172a0..89d90a3b9d6f 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -137,7 +137,7 @@ interface IActivityManager {
int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
int broadcastIntentWithFeature(in IApplicationThread caller, in String callingFeatureId,
in Intent intent, in String resolvedType, in IIntentReceiver resultTo, int resultCode,
- in String resultData, in Bundle map, in String[] requiredPermissions,
+ in String resultData, in Bundle map, in String[] requiredPermissions, in String[] excludePermissions,
int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId);
@UnsupportedAppUsage
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a60f1ca3cdcd..7ce0c7060b05 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1388,6 +1388,12 @@ public class Notification implements Parcelable
public static final String EXTRA_CALL_TYPE = "android.callType";
/**
+ * {@link #extras} key: whether the {@link android.app.Notification.CallStyle} notification
+ * is for a call that will activate video when answered. This extra is a boolean.
+ */
+ public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
+
+ /**
* {@link #extras} key: the person to be displayed as calling for the
* {@link android.app.Notification.CallStyle} notification. This extra is a {@link Person}.
*/
@@ -5110,6 +5116,7 @@ public class Notification implements Parcelable
TemplateBindResult result) {
p.headerless(resId == getBaseLayoutResource()
|| resId == getHeadsUpBaseLayoutResource()
+ || resId == getMessagingLayoutResource()
|| resId == R.layout.notification_template_material_media);
RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
@@ -6308,7 +6315,7 @@ public class Notification implements Parcelable
* Gets the theme's background color
*/
private @ColorInt int getDefaultBackgroundColor() {
- return obtainThemeColor(R.attr.colorBackground,
+ return obtainThemeColor(R.attr.colorSurface,
mInNightMode ? Color.BLACK : Color.WHITE);
}
@@ -6635,6 +6642,10 @@ public class Notification implements Parcelable
return R.layout.notification_template_material_messaging;
}
+ private int getBigMessagingLayoutResource() {
+ return R.layout.notification_template_material_big_messaging;
+ }
+
private int getConversationLayoutResource() {
return R.layout.notification_template_material_conversation;
}
@@ -8145,12 +8156,14 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeContentView(boolean increasedHeight) {
+ // All messaging templates contain the actions
ArrayList<Action> originalActions = mBuilder.mActions;
- mBuilder.mActions = new ArrayList<>();
- RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
- false /* hideLargeIcon */);
- mBuilder.mActions = originalActions;
- return remoteViews;
+ try {
+ mBuilder.mActions = new ArrayList<>();
+ return makeMessagingView(StandardTemplateParams.VIEW_TYPE_NORMAL);
+ } finally {
+ mBuilder.mActions = originalActions;
+ }
}
/**
@@ -8236,18 +8249,24 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeBigContentView() {
- return makeMessagingView(false /* isCollapsed */, true /* hideLargeIcon */);
+ return makeMessagingView(StandardTemplateParams.VIEW_TYPE_BIG);
}
/**
* Create a messaging layout.
*
- * @param isCollapsed Should this use the collapsed layout
- * @param hideRightIcons Should the reply affordance be shown at the end of the notification
+ * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_BIG,
+ * VIEW_TYPE_HEADS_UP
* @return the created remoteView.
*/
@NonNull
- private RemoteViews makeMessagingView(boolean isCollapsed, boolean hideRightIcons) {
+ private RemoteViews makeMessagingView(int viewType) {
+ boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_BIG;
+ boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL;
+ boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
+ boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
+ boolean isHeaderless = !isConversationLayout && isCollapsed;
+
CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
? super.mBigContentTitle
: mConversationTitle;
@@ -8265,23 +8284,26 @@ public class Notification implements Parcelable
} else {
isOneToOne = !isGroupConversation();
}
- boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
- boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
+ if (isHeaderless && isOneToOne && TextUtils.isEmpty(conversationTitle)) {
+ conversationTitle = getOtherPersonName();
+ }
+
Icon largeIcon = mBuilder.mN.mLargeIcon;
TemplateBindResult bindResult = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
- .viewType(isCollapsed ? StandardTemplateParams.VIEW_TYPE_NORMAL
- : StandardTemplateParams.VIEW_TYPE_BIG)
+ .viewType(viewType)
.highlightExpander(isConversationLayout)
.hideProgress(true)
- .title(conversationTitle)
+ .title(isHeaderless ? conversationTitle : null)
.text(null)
.hideLargeIcon(hideRightIcons || isOneToOne)
- .headerTextSecondary(conversationTitle);
+ .headerTextSecondary(isHeaderless ? null : conversationTitle);
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
isConversationLayout
? mBuilder.getConversationLayoutResource()
- : mBuilder.getMessagingLayoutResource(),
+ : isCollapsed
+ ? mBuilder.getMessagingLayoutResource()
+ : mBuilder.getBigMessagingLayoutResource(),
p,
bindResult);
if (isConversationLayout) {
@@ -8290,14 +8312,6 @@ public class Notification implements Parcelable
}
addExtras(mBuilder.mN.extras);
- if (!isConversationLayout) {
- // also update the end margin if there is an image
- // NOTE: This template doesn't support moving this icon to the left, so we don't
- // need to fully apply the MarginSet
- contentView.setViewLayoutMargin(R.id.notification_messaging, RemoteViews.MARGIN_END,
- bindResult.mHeadingExtraMarginSet.getDpValue(),
- TypedValue.COMPLEX_UNIT_DIP);
- }
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
mBuilder.getSmallIconColor(p));
contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
@@ -8323,6 +8337,10 @@ public class Notification implements Parcelable
contentView.setBoolean(R.id.status_bar_latest_event_content,
"setIsImportantConversation", isImportantConversation);
}
+ if (isHeaderless) {
+ // Collapsed legacy messaging style has a 1-line limit.
+ contentView.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
+ }
contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
largeIcon);
contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
@@ -8330,6 +8348,22 @@ public class Notification implements Parcelable
return contentView;
}
+ private CharSequence getKey(Person person) {
+ return person == null ? null
+ : person.getKey() == null ? person.getName() : person.getKey();
+ }
+
+ private CharSequence getOtherPersonName() {
+ CharSequence userKey = getKey(mUser);
+ for (int i = mMessages.size() - 1; i >= 0; i--) {
+ Person sender = mMessages.get(i).getSenderPerson();
+ if (sender != null && !TextUtils.equals(userKey, getKey(sender))) {
+ return sender.getName();
+ }
+ }
+ return null;
+ }
+
private boolean hasOnlyWhiteSpaceSenders() {
for (int i = 0; i < mMessages.size(); i++) {
Message m = mMessages.get(i);
@@ -8364,12 +8398,7 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
- true /* hideLargeIcon */);
- if (mConversationType == CONVERSATION_TYPE_LEGACY) {
- remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
- }
- return remoteViews;
+ return makeMessagingView(StandardTemplateParams.VIEW_TYPE_HEADS_UP);
}
public static final class Message {
@@ -9146,6 +9175,7 @@ public class Notification implements Parcelable
private PendingIntent mAnswerIntent;
private PendingIntent mDeclineIntent;
private PendingIntent mHangUpIntent;
+ private boolean mIsVideo;
private Integer mAnswerButtonColor;
private Integer mDeclineButtonColor;
private Icon mVerificationIcon;
@@ -9238,6 +9268,16 @@ public class Notification implements Parcelable
}
/**
+ * Sets whether the call is a video call, which may affect the icons or text used on the
+ * required action buttons.
+ */
+ @NonNull
+ public CallStyle setIsVideo(boolean isVideo) {
+ mIsVideo = isVideo;
+ return this;
+ }
+
+ /**
* Optional icon to be displayed with {@link #setVerificationText(CharSequence) text}
* as a verification status of the caller.
*/
@@ -9365,8 +9405,10 @@ public class Notification implements Parcelable
@Nullable
private Action makeAnswerAction() {
- return mAnswerIntent == null ? null : makeAction(R.drawable.ic_call_answer,
- R.string.call_notification_answer_action,
+ return mAnswerIntent == null ? null : makeAction(
+ mIsVideo ? R.drawable.ic_call_answer_video : R.drawable.ic_call_answer,
+ mIsVideo ? R.string.call_notification_answer_video_action
+ : R.string.call_notification_answer_action,
mAnswerButtonColor, R.color.call_notification_answer_color,
mAnswerIntent);
}
@@ -9545,6 +9587,7 @@ public class Notification implements Parcelable
public void addExtras(Bundle extras) {
super.addExtras(extras);
extras.putInt(EXTRA_CALL_TYPE, mCallType);
+ extras.putBoolean(EXTRA_CALL_IS_VIDEO, mIsVideo);
extras.putParcelable(EXTRA_CALL_PERSON, mPerson);
if (mVerificationIcon != null) {
extras.putParcelable(EXTRA_VERIFICATION_ICON, mVerificationIcon);
@@ -9587,6 +9630,7 @@ public class Notification implements Parcelable
protected void restoreFromExtras(Bundle extras) {
super.restoreFromExtras(extras);
mCallType = extras.getInt(EXTRA_CALL_TYPE);
+ mIsVideo = extras.getBoolean(EXTRA_CALL_IS_VIDEO);
mPerson = extras.getParcelable(EXTRA_CALL_PERSON);
mVerificationIcon = extras.getParcelable(EXTRA_VERIFICATION_ICON);
mVerificationText = extras.getCharSequence(EXTRA_VERIFICATION_TEXT);
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 2ceea7f1a6a8..0ab3f2f4be46 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -861,6 +861,19 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
}
/**
+ * Creates the base {@link Context} of this {@link Service}.
+ * Users may override this API to create customized base context.
+ *
+ * @see android.window.WindowProviderService WindowProviderService class for example
+ * @see ContextWrapper#attachBaseContext(Context)
+ *
+ * @hide
+ */
+ public Context createServiceBaseContext(ActivityThread mainThread, LoadedApk packageInfo) {
+ return ContextImpl.createAppContext(mainThread, packageInfo);
+ }
+
+ /**
* @hide
* Clean up any references to avoid leaks.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7af9482b0010..4dc044208a9f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -119,6 +119,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -1214,15 +1215,14 @@ public class DevicePolicyManager {
public @interface ProvisioningTrigger {}
/**
- * Possible values for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES}.
+ * Flags for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES}.
*
* @hide
*/
- @IntDef(prefix = { "SUPPORTED_MODES_" }, value = {
- SUPPORTED_MODES_ORGANIZATION_OWNED,
- SUPPORTED_MODES_PERSONALLY_OWNED,
- SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED,
- SUPPORTED_MODES_DEVICE_OWNER
+ @IntDef(flag = true, prefix = { "FLAG_SUPPORTED_MODES_" }, value = {
+ FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED,
+ FLAG_SUPPORTED_MODES_PERSONALLY_OWNED,
+ FLAG_SUPPORTED_MODES_DEVICE_OWNER
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProvisioningConfiguration {}
@@ -1307,7 +1307,7 @@ public class DevicePolicyManager {
public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4;
/**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
+ * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
* organization-owned.
*
* <p>Using this value indicates the admin app can only be provisioned in either a
@@ -1316,55 +1316,48 @@ public class DevicePolicyManager {
* #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra contain {@link
* #PROVISIONING_MODE_MANAGED_PROFILE} and {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}.
*
- * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
+ * <p>Also, if this flag is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
* will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
* #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
*
+ * <p>This flag can be combined with {@link #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED}. In
+ * that case, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity will have
+ * the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra contain {@link
+ * #PROVISIONING_MODE_MANAGED_PROFILE}, {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE} and
+ * {@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE}.
+ *
* @hide
*/
@SystemApi
- public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1;
+ public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1;
/**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
- * personally-owned.
+ * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning
+ * is personally-owned.
*
- * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+ * <p>Using this flag will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
* activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
* contain only {@link #PROVISIONING_MODE_MANAGED_PROFILE}.
*
- * @hide
- */
- @SystemApi
- public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2;
-
- /**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning could
- * be organization-owned or personally-owned.
- *
- * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
- * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
- * contain {@link
+ * <p>This flag can be combined with {@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}. In
+ * that case, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity will have the
+ * {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra contain {@link
* #PROVISIONING_MODE_MANAGED_PROFILE}, {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE} and
* {@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE}.
*
- * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
- * will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
- * #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
- *
* @hide
*/
@SystemApi
- public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3;
+ public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 1 << 1;
/**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that the only supported
- * provisioning mode is device owner.
+ * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that the only
+ * supported provisioning mode is device owner.
*
* @hide
*/
@SystemApi
- public static final int SUPPORTED_MODES_DEVICE_OWNER = 4;
+ public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 1 << 2;
/**
* This MIME type is used for starting the device owner provisioning.
@@ -2637,7 +2630,7 @@ public class DevicePolicyManager {
* An integer extra indication what provisioning modes should be available for the admin app
* to pick.
*
- * <p>The default value is {@link #SUPPORTED_MODES_ORGANIZATION_OWNED}.
+ * <p>The default value is {@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}.
*
* <p>The value of this extra will determine the contents of the {@link
* #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array that is passed to the admin app as an
@@ -2648,13 +2641,21 @@ public class DevicePolicyManager {
* #ACTION_GET_PROVISIONING_MODE} activity via the {@link #EXTRA_PROVISIONING_IMEI} and {@link
* #EXTRA_PROVISIONING_SERIAL_NUMBER} respectively.
*
+ * <p>The allowed flag combinations are:
+ * <ul>
+ * <li>{@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}</li>
+ * <li>{@link #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED}</li>
+ * <li>{@link #FLAG_SUPPORTED_MODES_DEVICE_OWNER}</li>
+ * <li>{@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}
+ * | {@link #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED}</li>
+ * </ul>
+ *
* <p>This extra is only respected when provided alongside the {@link
* #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent action.
*
- * @see #SUPPORTED_MODES_ORGANIZATION_OWNED
- * @see #SUPPORTED_MODES_PERSONALLY_OWNED
- * @see #SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
- * @see #SUPPORTED_MODES_DEVICE_OWNER
+ * @see #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED
+ * @see #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED
+ * @see #FLAG_SUPPORTED_MODES_DEVICE_OWNER
* @hide
*/
@SystemApi
@@ -6460,12 +6461,14 @@ public class DevicePolicyManager {
* to a given KeyChain key.
*
* Key are granted on a per-UID basis, so if several apps share the same UID, granting access to
- * one of them automatically grants it to others. This method returns a set of sets of package
- * names, where each internal set contains all packages sharing the same UID. Grantee packages
- * that don't share UID with other packages are represented by singleton sets.
+ * one of them automatically grants it to others. This method returns a map containing one entry
+ * per grantee UID. Entries have UIDs as keys and sets of corresponding package names as values.
+ * In particular, grantee packages that don't share UID with other packages are represented by
+ * entries having singleton sets as values.
*
* @param alias The alias of the key to grant access to.
- * @return package names of apps that have access to a given key, grouped by UIDs
+ * @return apps that have access to a given key, arranged in a map from UID to sets of
+ * package names.
*
* @throws SecurityException if the caller is not a device owner, a profile owner or
* delegated certificate chooser.
@@ -6473,26 +6476,11 @@ public class DevicePolicyManager {
*
* @see #grantKeyPairToApp(ComponentName, String, String)
*/
- public @NonNull Set<Set<String>> getKeyPairGrants(@NonNull String alias) {
+ public @NonNull Map<Integer, Set<String>> getKeyPairGrants(@NonNull String alias) {
throwIfParentInstance("getKeyPairGrants");
try {
- // Set of sets is flattened into a null-separated list.
- final List<String> flattened =
- mService.getKeyPairGrants(mContext.getPackageName(), alias);
- final Set<Set<String>> result = new HashSet<>();
- Set<String> pkgsForOneUid = new HashSet<>();
- for (final String pkg : flattened) {
- if (pkg == null) {
- result.add(pkgsForOneUid);
- pkgsForOneUid = new HashSet<>();
- } else {
- pkgsForOneUid.add(pkg);
- }
- }
- if (!pkgsForOneUid.isEmpty()) {
- result.add(pkgsForOneUid);
- }
- return result;
+ // The result is wrapped into intermediate parcelable representation.
+ return mService.getKeyPairGrants(mContext.getPackageName(), alias).getPackagesByUid();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 05b0be4c5813..8e86f6545f23 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@ package android.app.admin;
import android.app.admin.NetworkEvent;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
+import android.app.admin.ParcelableGranteeMap;
import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
@@ -485,7 +486,7 @@ interface IDevicePolicyManager {
boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags);
boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
- List<String> getKeyPairGrants(in String callerPackage, in String alias);
+ ParcelableGranteeMap getKeyPairGrants(in String callerPackage, in String alias);
boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant);
boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias);
diff --git a/core/java/android/app/admin/ParcelableGranteeMap.aidl b/core/java/android/app/admin/ParcelableGranteeMap.aidl
new file mode 100644
index 000000000000..cd15b4901472
--- /dev/null
+++ b/core/java/android/app/admin/ParcelableGranteeMap.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+parcelable ParcelableGranteeMap; \ No newline at end of file
diff --git a/core/java/android/app/admin/ParcelableGranteeMap.java b/core/java/android/app/admin/ParcelableGranteeMap.java
new file mode 100644
index 000000000000..be348ad067c9
--- /dev/null
+++ b/core/java/android/app/admin/ParcelableGranteeMap.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Class for marshalling keypair grantees for a given KeyChain key via Binder.
+ *
+ * @hide
+ */
+public class ParcelableGranteeMap implements Parcelable {
+
+ private final Map<Integer, Set<String>> mPackagesByUid;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPackagesByUid.size());
+ for (final Map.Entry<Integer, Set<String>> uidEntry : mPackagesByUid.entrySet()) {
+ dest.writeInt(uidEntry.getKey());
+ dest.writeStringArray(uidEntry.getValue().toArray(new String[0]));
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<ParcelableGranteeMap> CREATOR =
+ new Parcelable.Creator<ParcelableGranteeMap>() {
+ @Override
+ public ParcelableGranteeMap createFromParcel(Parcel source) {
+ final Map<Integer, Set<String>> packagesByUid = new ArrayMap<>();
+ final int numUids = source.readInt();
+ for (int i = 0; i < numUids; i++) {
+ final int uid = source.readInt();
+ final String[] pkgs = source.readStringArray();
+ packagesByUid.put(uid, new ArraySet<>(pkgs));
+ }
+ return new ParcelableGranteeMap(packagesByUid);
+ }
+
+ @Override
+ public ParcelableGranteeMap[] newArray(int size) {
+ return new ParcelableGranteeMap[size];
+ }
+ };
+
+ /**
+ * Creates an instance holding a reference (not a copy) to the given map.
+ */
+ public ParcelableGranteeMap(@NonNull Map<Integer, Set<String>> packagesByUid) {
+ mPackagesByUid = packagesByUid;
+ }
+
+ /**
+ * Returns a reference (not a copy) to the stored map.
+ */
+ @NonNull
+ public Map<Integer, Set<String>> getPackagesByUid() {
+ return mPackagesByUid;
+ }
+}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 2a50e0de2145..eb4c624be0b2 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -65,6 +65,7 @@ interface IUsageStatsManager {
void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs,
String callingPackage);
void reportUsageStop(in IBinder activity, String token, String callingPackage);
+ void reportUserInteraction(String packageName, int userId);
int getUsageSource();
void forceUsageSourceSettingRead();
long getLastTimeAnyComponentUsed(String packageName);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 542473a3d2a9..e8175c709d85 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -982,6 +982,20 @@ public final class UsageStatsManager {
}
/**
+ * Reports user interaction with a given package in the given user.
+ *
+ * <p><em>This method is only for use by the system</em>
+ * @hide
+ */
+ public void reportUserInteraction(@NonNull String packageName, int userId) {
+ try {
+ mService.reportUserInteraction(packageName, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Report usage associated with a particular {@code token} has started. Tokens are app defined
* strings used to represent usage of in-app features. Apps with the {@link
* android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time limit observers
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 79fd8072f9f0..236185e2a28d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3095,8 +3095,6 @@ public final class BluetoothAdapter {
*
* @param transport - whether the {@link OobData} is generated for LE or Classic.
* @param oobData - data generated in the host stack(LE) or controller (Classic)
- *
- * @hide
*/
void onOobData(@Transport int transport, @Nullable OobData oobData);
@@ -3104,8 +3102,6 @@ public final class BluetoothAdapter {
* Provides feedback when things don't go as expected.
*
* @param errorCode - the code descibing the type of error that occurred.
- *
- * @hide
*/
void onError(@OobError int errorCode);
}
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index 08d694eb93e2..d6868e0ffd5c 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -830,7 +830,7 @@ public final class OobData implements Parcelable {
@Nullable
@SystemApi
public byte[] getLeAppearance() {
- return mLeTemporaryKey;
+ return mLeAppearance;
}
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 09ac8103c526..318913f3bec0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2208,6 +2208,17 @@ public abstract class Context {
}
/**
+ * Like {@link #sendBroadcastMultiplePermissions(Intent, String[])}, but also allows
+ * specification of a list of excluded permissions. This allows sending a broadcast to an
+ * app that has the permissions in `receiverPermissions` but not `excludedPermissions`.
+ * @hide
+ */
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Broadcast the given intent to all interested BroadcastReceivers, allowing
* an array of required permissions to be enforced. This call is asynchronous; it returns
* immediately, and you will continue executing while the receivers are run. No results are
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 8936d0c47a58..dddcbea63872 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -493,6 +493,13 @@ public class ContextWrapper extends Context {
/** @hide */
@Override
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
+ mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions);
+ }
+
+ /** @hide */
+ @Override
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
String[] receiverPermissions) {
mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9ad017c5f9c6..f8d407db07a5 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2871,6 +2871,7 @@ public class Intent implements Parcelable, Cloneable {
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_FULLY_LOADED =
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttribution.java b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
index 3a4aae19d459..4ec2e73a0b83 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+++ b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
@@ -40,7 +40,7 @@ public class ParsedAttribution implements Parcelable {
public static final int MAX_ATTRIBUTION_TAG_LEN = 50;
/** Maximum amount of attributions per package */
- private static final int MAX_NUM_ATTRIBUTIONS = 1000;
+ private static final int MAX_NUM_ATTRIBUTIONS = 10000;
/** Tag of the attribution */
public final @NonNull String tag;
@@ -100,7 +100,7 @@ public class ParsedAttribution implements Parcelable {
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -215,8 +215,8 @@ public class ParsedAttribution implements Parcelable {
};
@DataClass.Generated(
- time = 1607463855175L,
- codegenVersion = "1.0.22",
+ time = 1618351459610L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java",
inputSignatures = "public static final int MAX_ATTRIBUTION_TAG_LEN\nprivate static final int MAX_NUM_ATTRIBUTIONS\npublic final @android.annotation.NonNull java.lang.String tag\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
@Deprecated
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
index adc668f8fa02..77bd14756637 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
@@ -32,7 +32,9 @@ import android.os.UserHandle;
import com.android.internal.util.CollectionUtils;
+import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -350,6 +352,8 @@ public final class DomainVerificationManager {
*
* The set will be ordered from lowest to highest priority.
*
+ * @param domain The host to query for. An invalid domain will result in an empty set.
+ *
* @hide
*/
@SystemApi
@@ -357,11 +361,11 @@ public final class DomainVerificationManager {
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
public SortedSet<DomainOwner> getOwnersForDomain(@NonNull String domain) {
try {
+ Objects.requireNonNull(domain);
final List<DomainOwner> orderedList = mDomainVerificationManager.getOwnersForDomain(
domain, mContext.getUserId());
SortedSet<DomainOwner> set = new TreeSet<>(
- (first, second) -> Integer.compare(orderedList.indexOf(first),
- orderedList.indexOf(second)));
+ Comparator.comparingInt(orderedList::indexOf));
set.addAll(orderedList);
return set;
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
index 62d727c080e3..1268658d75f5 100644
--- a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
@@ -16,11 +16,9 @@
package android.hardware.biometrics;
-import android.hardware.biometrics.BiometricSourceType;
-
/**
* @hide
*/
oneway interface IBiometricEnabledOnKeyguardCallback {
- void onChanged(in BiometricSourceType type, boolean enabled, int userId);
+ void onChanged(boolean enabled, int userId);
} \ No newline at end of file
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 5f65d46f3b1e..662ebb356f4c 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -78,10 +78,8 @@ public class VpnManager {
/**
* An IPsec VPN created by the built-in LegacyVpnRunner.
- * @deprecated new Android devices should use VPN_TYPE_PLATFORM instead.
* @hide
*/
- @Deprecated
@SystemApi(client = MODULE_LIBRARIES)
public static final int TYPE_VPN_LEGACY = 3;
@@ -418,4 +416,4 @@ public class VpnManager {
throw e.rethrowFromSystemServer();
}
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 75db3820f5e7..d7c6fa1822b9 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -79,7 +79,12 @@ public final class VcnGatewayConnectionConfig {
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int MIN_MTU_V6 = 1280;
- private static final Set<Integer> ALLOWED_CAPABILITIES;
+ /**
+ * The set of allowed capabilities for exposed capabilities.
+ *
+ * @hide
+ */
+ public static final Set<Integer> ALLOWED_CAPABILITIES;
static {
Set<Integer> allowedCaps = new ArraySet<>();
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 033148379041..ba63ba4521df 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -36,7 +36,7 @@ public abstract class BatteryConsumer {
* @hide
*/
@IntDef(prefix = {"POWER_COMPONENT_"}, value = {
- POWER_COMPONENT_USAGE,
+ POWER_COMPONENT_SCREEN,
POWER_COMPONENT_CPU,
POWER_COMPONENT_BLUETOOTH,
POWER_COMPONENT_CAMERA,
@@ -49,14 +49,16 @@ public abstract class BatteryConsumer {
POWER_COMPONENT_GNSS,
POWER_COMPONENT_WIFI,
POWER_COMPONENT_WAKELOCK,
- POWER_COMPONENT_SCREEN,
+ POWER_COMPONENT_MEMORY,
+ POWER_COMPONENT_PHONE,
+ POWER_COMPONENT_IDLE,
POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface PowerComponent {
}
- public static final int POWER_COMPONENT_USAGE = 0;
+ public static final int POWER_COMPONENT_SCREEN = 0;
public static final int POWER_COMPONENT_CPU = 1;
public static final int POWER_COMPONENT_BLUETOOTH = 2;
public static final int POWER_COMPONENT_CAMERA = 3;
@@ -69,13 +71,15 @@ public abstract class BatteryConsumer {
public static final int POWER_COMPONENT_GNSS = 10;
public static final int POWER_COMPONENT_WIFI = 11;
public static final int POWER_COMPONENT_WAKELOCK = 12;
- public static final int POWER_COMPONENT_SCREEN = 13;
+ public static final int POWER_COMPONENT_MEMORY = 13;
+ public static final int POWER_COMPONENT_PHONE = 13;
+ public static final int POWER_COMPONENT_IDLE = 15;
// Power that is re-attributed to other battery consumers. For example, for System Server
// this represents the power attributed to apps requesting system services.
// The value should be negative or zero.
- public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 14;
+ public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 16;
- public static final int POWER_COMPONENT_COUNT = 15;
+ public static final int POWER_COMPONENT_COUNT = 17;
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
@@ -87,7 +91,7 @@ public abstract class BatteryConsumer {
* @hide
*/
@IntDef(prefix = {"TIME_COMPONENT_"}, value = {
- TIME_COMPONENT_USAGE,
+ TIME_COMPONENT_SCREEN,
TIME_COMPONENT_CPU,
TIME_COMPONENT_CPU_FOREGROUND,
TIME_COMPONENT_BLUETOOTH,
@@ -98,13 +102,15 @@ public abstract class BatteryConsumer {
TIME_COMPONENT_GNSS,
TIME_COMPONENT_WIFI,
TIME_COMPONENT_WAKELOCK,
- TIME_COMPONENT_SCREEN,
+ TIME_COMPONENT_MEMORY,
+ TIME_COMPONENT_PHONE,
+ TIME_COMPONENT_IDLE,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface TimeComponent {
}
- public static final int TIME_COMPONENT_USAGE = 0;
+ public static final int TIME_COMPONENT_SCREEN = 0;
public static final int TIME_COMPONENT_CPU = 1;
public static final int TIME_COMPONENT_CPU_FOREGROUND = 2;
public static final int TIME_COMPONENT_BLUETOOTH = 3;
@@ -117,9 +123,11 @@ public abstract class BatteryConsumer {
public static final int TIME_COMPONENT_GNSS = 10;
public static final int TIME_COMPONENT_WIFI = 11;
public static final int TIME_COMPONENT_WAKELOCK = 12;
- public static final int TIME_COMPONENT_SCREEN = 13;
+ public static final int TIME_COMPONENT_MEMORY = 13;
+ public static final int TIME_COMPONENT_PHONE = 14;
+ public static final int TIME_COMPONENT_IDLE = 15;
- public static final int TIME_COMPONENT_COUNT = 14;
+ public static final int TIME_COMPONENT_COUNT = 16;
public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
@@ -148,7 +156,7 @@ public abstract class BatteryConsumer {
*/
public static final int POWER_MODEL_MEASURED_ENERGY = 1;
- private final PowerComponents mPowerComponents;
+ protected final PowerComponents mPowerComponents;
protected BatteryConsumer(@NonNull PowerComponents powerComponents) {
mPowerComponents = powerComponents;
@@ -192,6 +200,23 @@ public abstract class BatteryConsumer {
return mPowerComponents.getConsumedPowerForCustomComponent(componentId);
}
+ public int getCustomPowerComponentCount() {
+ return mPowerComponents.getCustomPowerComponentCount();
+ }
+
+ void setCustomPowerComponentNames(String[] customPowerComponentNames) {
+ mPowerComponents.setCustomPowerComponentNames(customPowerComponentNames);
+ }
+
+ /**
+ * Returns the name of the specified power component.
+ *
+ * @param componentId The ID of the custom power component.
+ */
+ public String getCustomPowerComponentName(int componentId) {
+ return mPowerComponents.getCustomPowerComponentName(componentId);
+ }
+
/**
* Returns the amount of time since BatteryStats reset used by the specified component, e.g.
* CPU, WiFi etc.
@@ -222,9 +247,9 @@ public abstract class BatteryConsumer {
protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
final PowerComponents.Builder mPowerComponentsBuilder;
- public BaseBuilder(int customPowerComponentCount, int customTimeComponentCount,
- boolean includePowerModels) {
- mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentCount,
+ public BaseBuilder(@NonNull String[] customPowerComponentNames,
+ int customTimeComponentCount, boolean includePowerModels) {
+ mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentNames,
customTimeComponentCount, includePowerModels);
}
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index f2887748f460..8ea59ce37018 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -39,9 +39,10 @@ public final class BatteryUsageStats implements Parcelable {
private final double mDischargedPowerUpperBound;
private final long mBatteryTimeRemainingMs;
private final long mChargeTimeRemainingMs;
- private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
- private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
- private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
+ private final String[] mCustomPowerComponentNames;
+ private final List<UidBatteryConsumer> mUidBatteryConsumers;
+ private final List<SystemBatteryConsumer> mSystemBatteryConsumers;
+ private final List<UserBatteryConsumer> mUserBatteryConsumers;
private final Parcel mHistoryBuffer;
private final List<BatteryStats.HistoryTag> mHistoryTagPool;
@@ -54,6 +55,7 @@ public final class BatteryUsageStats implements Parcelable {
mHistoryTagPool = builder.mHistoryTagPool;
mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
+ mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
double totalPower = 0;
@@ -182,12 +184,31 @@ public final class BatteryUsageStats implements Parcelable {
mDischargedPowerUpperBound = source.readDouble();
mBatteryTimeRemainingMs = source.readLong();
mChargeTimeRemainingMs = source.readLong();
- mUidBatteryConsumers = new ArrayList<>();
- source.readParcelableList(mUidBatteryConsumers, getClass().getClassLoader());
- mSystemBatteryConsumers = new ArrayList<>();
- source.readParcelableList(mSystemBatteryConsumers, getClass().getClassLoader());
- mUserBatteryConsumers = new ArrayList<>();
- source.readParcelableList(mUserBatteryConsumers, getClass().getClassLoader());
+ mCustomPowerComponentNames = source.readStringArray();
+ int uidCount = source.readInt();
+ mUidBatteryConsumers = new ArrayList<>(uidCount);
+ for (int i = 0; i < uidCount; i++) {
+ final UidBatteryConsumer consumer =
+ UidBatteryConsumer.CREATOR.createFromParcel(source);
+ consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
+ mUidBatteryConsumers.add(consumer);
+ }
+ int sysCount = source.readInt();
+ mSystemBatteryConsumers = new ArrayList<>(sysCount);
+ for (int i = 0; i < sysCount; i++) {
+ final SystemBatteryConsumer consumer =
+ SystemBatteryConsumer.CREATOR.createFromParcel(source);
+ consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
+ mSystemBatteryConsumers.add(consumer);
+ }
+ int userCount = source.readInt();
+ mUserBatteryConsumers = new ArrayList<>(userCount);
+ for (int i = 0; i < userCount; i++) {
+ final UserBatteryConsumer consumer =
+ UserBatteryConsumer.CREATOR.createFromParcel(source);
+ consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
+ mUserBatteryConsumers.add(consumer);
+ }
if (source.readBoolean()) {
mHistoryBuffer = Parcel.obtain();
mHistoryBuffer.setDataSize(0);
@@ -222,9 +243,19 @@ public final class BatteryUsageStats implements Parcelable {
dest.writeDouble(mDischargedPowerUpperBound);
dest.writeLong(mBatteryTimeRemainingMs);
dest.writeLong(mChargeTimeRemainingMs);
- dest.writeParcelableList(mUidBatteryConsumers, flags);
- dest.writeParcelableList(mSystemBatteryConsumers, flags);
- dest.writeParcelableList(mUserBatteryConsumers, flags);
+ dest.writeStringArray(mCustomPowerComponentNames);
+ dest.writeInt(mUidBatteryConsumers.size());
+ for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
+ mUidBatteryConsumers.get(i).writeToParcel(dest, flags);
+ }
+ dest.writeInt(mSystemBatteryConsumers.size());
+ for (int i = mSystemBatteryConsumers.size() - 1; i >= 0; i--) {
+ mSystemBatteryConsumers.get(i).writeToParcel(dest, flags);
+ }
+ dest.writeInt(mUserBatteryConsumers.size());
+ for (int i = mUserBatteryConsumers.size() - 1; i >= 0; i--) {
+ mUserBatteryConsumers.get(i).writeToParcel(dest, flags);
+ }
if (mHistoryBuffer != null) {
dest.writeBoolean(true);
@@ -259,7 +290,8 @@ public final class BatteryUsageStats implements Parcelable {
* Builder for BatteryUsageStats.
*/
public static final class Builder {
- private final int mCustomPowerComponentCount;
+ @NonNull
+ private final String[] mCustomPowerComponentNames;
private final int mCustomTimeComponentCount;
private final boolean mIncludePowerModels;
private long mStatsStartTimestampMs;
@@ -277,13 +309,13 @@ public final class BatteryUsageStats implements Parcelable {
private Parcel mHistoryBuffer;
private List<BatteryStats.HistoryTag> mHistoryTagPool;
- public Builder(int customPowerComponentCount, int customTimeComponentCount) {
- this(customPowerComponentCount, customTimeComponentCount, false);
+ public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount) {
+ this(customPowerComponentNames, customTimeComponentCount, false);
}
- public Builder(int customPowerComponentCount, int customTimeComponentCount,
+ public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels) {
- mCustomPowerComponentCount = customPowerComponentCount;
+ mCustomPowerComponentNames = customPowerComponentNames;
mCustomTimeComponentCount = customTimeComponentCount;
mIncludePowerModels = includePowerModels;
}
@@ -366,7 +398,7 @@ public final class BatteryUsageStats implements Parcelable {
int uid = batteryStatsUid.getUid();
UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid);
if (builder == null) {
- builder = new UidBatteryConsumer.Builder(mCustomPowerComponentCount,
+ builder = new UidBatteryConsumer.Builder(mCustomPowerComponentNames,
mCustomTimeComponentCount, mIncludePowerModels, batteryStatsUid);
mUidBatteryConsumerBuilders.put(uid, builder);
}
@@ -382,7 +414,7 @@ public final class BatteryUsageStats implements Parcelable {
@SystemBatteryConsumer.DrainType int drainType) {
SystemBatteryConsumer.Builder builder = mSystemBatteryConsumerBuilders.get(drainType);
if (builder == null) {
- builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentCount,
+ builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentNames,
mCustomTimeComponentCount, mIncludePowerModels, drainType);
mSystemBatteryConsumerBuilders.put(drainType, builder);
}
@@ -397,7 +429,7 @@ public final class BatteryUsageStats implements Parcelable {
public UserBatteryConsumer.Builder getOrCreateUserBatteryConsumerBuilder(int userId) {
UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId);
if (builder == null) {
- builder = new UserBatteryConsumer.Builder(mCustomPowerComponentCount,
+ builder = new UserBatteryConsumer.Builder(mCustomPowerComponentNames,
mCustomTimeComponentCount, mIncludePowerModels, userId);
mUserBatteryConsumerBuilders.put(userId, builder);
}
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 238f4518b7d3..a0a41f4d6630 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -26,7 +26,7 @@ import android.annotation.NonNull;
class PowerComponents {
private static final int CUSTOM_POWER_COMPONENT_OFFSET = BatteryConsumer.POWER_COMPONENT_COUNT
- BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
- public static final int CUSTOM_TIME_COMPONENT_OFFSET = BatteryConsumer.TIME_COMPONENT_COUNT
+ private static final int CUSTOM_TIME_COMPONENT_OFFSET = BatteryConsumer.TIME_COMPONENT_COUNT
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID;
private final double mTotalConsumedPowerMah;
@@ -34,9 +34,12 @@ class PowerComponents {
private final long[] mTimeComponentsMs;
private final int mCustomPowerComponentCount;
private final byte[] mPowerModels;
+ // Not written to Parcel and must be explicitly restored during the parent object's unparceling
+ private String[] mCustomPowerComponentNames;
PowerComponents(@NonNull Builder builder) {
- mCustomPowerComponentCount = builder.mCustomPowerComponentCount;
+ mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
+ mCustomPowerComponentCount = mCustomPowerComponentNames.length;
mPowerComponentsMah = builder.mPowerComponentsMah;
mTimeComponentsMs = builder.mTimeComponentsMs;
mTotalConsumedPowerMah = builder.getTotalPower();
@@ -117,6 +120,26 @@ class PowerComponents {
}
}
+ void setCustomPowerComponentNames(String[] customPowerComponentNames) {
+ mCustomPowerComponentNames = customPowerComponentNames;
+ }
+
+ public String getCustomPowerComponentName(int componentId) {
+ if (componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+ && componentId < BatteryConsumer.LAST_CUSTOM_POWER_COMPONENT_ID) {
+ try {
+ return mCustomPowerComponentNames[componentId
+ - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException(
+ "Unsupported custom power component ID: " + componentId);
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported custom power component ID: " + componentId);
+ }
+ }
+
@BatteryConsumer.PowerModel
int getPowerModel(@BatteryConsumer.PowerComponent int component) {
if (mPowerModels == null) {
@@ -164,20 +187,37 @@ class PowerComponents {
}
}
+ public int getCustomPowerComponentCount() {
+ return mCustomPowerComponentCount;
+ }
+
+ /**
+ * Returns the largest usage duration among all time components.
+ */
+ public long getMaxComponentUsageDurationMillis() {
+ long max = 0;
+ for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) {
+ if (mTimeComponentsMs[i] > max) {
+ max = mTimeComponentsMs[i];
+ }
+ }
+ return max;
+ }
+
/**
* Builder for PowerComponents.
*/
static final class Builder {
private final double[] mPowerComponentsMah;
- private final int mCustomPowerComponentCount;
+ private final String[] mCustomPowerComponentNames;
private final long[] mTimeComponentsMs;
private final byte[] mPowerModels;
- Builder(int customPowerComponentCount, int customTimeComponentCount,
+ Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels) {
- mCustomPowerComponentCount = customPowerComponentCount;
+ mCustomPowerComponentNames = customPowerComponentNames;
int powerComponentCount =
- BatteryConsumer.POWER_COMPONENT_COUNT + customPowerComponentCount;
+ BatteryConsumer.POWER_COMPONENT_COUNT + mCustomPowerComponentNames.length;
mPowerComponentsMah = new double[powerComponentCount];
mTimeComponentsMs =
new long[BatteryConsumer.TIME_COMPONENT_COUNT + customTimeComponentCount];
@@ -285,10 +325,10 @@ class PowerComponents {
}
public void addPowerAndDuration(Builder other) {
- for (int i = 0; i < mPowerComponentsMah.length; i++) {
+ for (int i = mPowerComponentsMah.length - 1; i >= 0; i--) {
mPowerComponentsMah[i] += other.mPowerComponentsMah[i];
}
- for (int i = 0; i < mTimeComponentsMs.length; i++) {
+ for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) {
mTimeComponentsMs[i] += other.mTimeComponentsMs[i];
}
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index a42448c261d4..b474d7c95996 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -169,8 +169,9 @@ public class RecoverySystem {
public @interface ResumeOnRebootRebootErrorCode {}
/**
- * The preparation of resume on reboot succeeds. Don't expose it because a successful reboot
- * should just reboot the device.
+ * The preparation of resume on reboot succeeds.
+ *
+ * <p> Don't expose it because a successful reboot should just reboot the device.
* @hide
*/
public static final int RESUME_ON_REBOOT_REBOOT_ERROR_NONE = 0;
diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java
index e973e4c1044e..1327978ad0ba 100644
--- a/core/java/android/os/SystemBatteryConsumer.java
+++ b/core/java/android/os/SystemBatteryConsumer.java
@@ -104,6 +104,13 @@ public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable
}
/**
+ * Returns the amount of time this consumer was operating.
+ */
+ public long getUsageDurationMillis() {
+ return mPowerComponents.getMaxComponentUsageDurationMillis();
+ }
+
+ /**
* Writes the contents into a Parcel.
*/
@Override
@@ -140,9 +147,9 @@ public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable
private double mPowerConsumedByAppsMah;
private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
- Builder(int customPowerComponentCount, int customTimeComponentCount,
+ Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels, @DrainType int drainType) {
- super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
mDrainType = drainType;
}
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 87c263b3dd38..92e960344f3e 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -139,9 +139,9 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
public long mTimeInBackgroundMs;
private boolean mExcludeFromBatteryUsageStats;
- public Builder(int customPowerComponentCount, int customTimeComponentCount,
+ public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid) {
- super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
mBatteryStatsUid = batteryStatsUid;
mUid = batteryStatsUid.getUid();
}
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
index 78322088a3a4..de0a707fb656 100644
--- a/core/java/android/os/UserBatteryConsumer.java
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -77,9 +77,9 @@ public class UserBatteryConsumer extends BatteryConsumer implements Parcelable {
private final int mUserId;
private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
- Builder(int customPowerComponentCount, int customTimeComponentCount,
+ Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels, int userId) {
- super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
mUserId = userId;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 9bfd75ef2170..51f19ebee987 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -22,10 +22,10 @@ import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.LongDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.UserHandleAware;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -129,7 +129,7 @@ public class CallLog {
public static final int ERROR_STORAGE_FULL = 2;
/**
- * Indicates that the {@link InputStream} passed to {@link #storeCallComposerPictureAsUser}
+ * Indicates that the {@link InputStream} passed to {@link #storeCallComposerPicture}
* was closed.
*
* The caller should retry if this error is encountered, and be sure to not close the stream
@@ -195,9 +195,8 @@ public class CallLog {
* The caller is responsible for closing the {@link InputStream} after the callback indicating
* success or failure.
*
- * @param context An instance of {@link Context}.
- * @param user The user for whom the picture is stored. If {@code null}, the picture will be
- * stored for all users.
+ * @param context An instance of {@link Context}. The picture will be stored to the user
+ * corresponding to {@link Context#getUser()}.
* @param input An input stream from which the picture to store should be read. The input data
* must be decodeable as either a JPEG, PNG, or GIF image.
* @param executor The {@link Executor} on which to perform the file transfer operation and
@@ -207,12 +206,12 @@ public class CallLog {
* @hide
*/
@SystemApi
+ @UserHandleAware
@RequiresPermission(allOf = {
Manifest.permission.WRITE_CALL_LOG,
Manifest.permission.INTERACT_ACROSS_USERS
})
- public static void storeCallComposerPictureAsUser(@NonNull Context context,
- @Nullable UserHandle user,
+ public static void storeCallComposerPicture(@NonNull Context context,
@NonNull InputStream input,
@CallbackExecutor @NonNull Executor executor,
@NonNull OutcomeReceiver<Uri, CallComposerLoggingException> callback) {
@@ -246,12 +245,13 @@ public class CallLog {
byte[] picData = tmpOut.toByteArray();
UserManager userManager = context.getSystemService(UserManager.class);
+ UserHandle user = context.getUser();
// Nasty casework for the shadow calllog begins...
// First see if we're just inserting for one user. If so, insert into the shadow
// based on whether that user is unlocked.
UserHandle realUser = UserHandle.CURRENT.equals(user)
? android.os.Process.myUserHandle() : user;
- if (realUser != null) {
+ if (realUser != UserHandle.ALL) {
Uri baseUri = userManager.isUserUnlocked(realUser) ? CALL_COMPOSER_PICTURE_URI
: SHADOW_CALL_COMPOSER_PICTURE_URI;
Uri pictureInsertionUri = ContentProvider.maybeAddUserId(baseUri,
@@ -625,7 +625,7 @@ public class CallLog {
}
/**
- * @param pictureUri {@link Uri} returned from {@link #storeCallComposerPictureAsUser}.
+ * @param pictureUri {@link Uri} returned from {@link #storeCallComposerPicture}.
* Associates that stored picture with this call in the log.
*/
public @NonNull AddCallParametersBuilder setPictureUri(@NonNull Uri pictureUri) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9450994af89f..2616a6676db1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9136,6 +9136,20 @@ public final class Settings {
"biometric_debug_enabled";
/**
+ * Whether or not biometric is allowed on Keyguard.
+ * @hide
+ */
+ @Readable
+ public static final String BIOMETRIC_KEYGUARD_ENABLED = "biometric_keyguard_enabled";
+
+ /**
+ * Whether or not biometric is allowed for apps (through BiometricPrompt).
+ * @hide
+ */
+ @Readable
+ public static final String BIOMETRIC_APP_ENABLED = "biometric_app_enabled";
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index bed77e664337..95024b38575b 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -24,9 +24,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.content.AttributionSource;
import android.content.Context;
-import android.content.ContextParams;
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.PersistableBundle;
@@ -49,7 +47,7 @@ import java.util.concurrent.Executor;
@SystemApi
@SystemService(Context.UWB_SERVICE)
public final class UwbManager {
- private static final String SERVICE_NAME = "uwb";
+ private static final String SERVICE_NAME = Context.UWB_SERVICE;
private final Context mContext;
private final IUwbAdapter mUwbAdapter;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e4500611db9c..21f75d419a5e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -104,6 +104,7 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeApplyTransaction(long transactionObj, boolean sync);
private static native void nativeMergeTransaction(long transactionObj,
long otherTransactionObj);
+ private static native void nativeClearTransaction(long transactionObj);
private static native void nativeSetAnimationTransaction(long transactionObj);
private static native void nativeSetEarlyWakeupStart(long transactionObj);
private static native void nativeSetEarlyWakeupEnd(long transactionObj);
@@ -2602,6 +2603,19 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Clear the transaction object, without applying it.
+ *
+ * @hide
+ */
+ public void clear() {
+ mResizedSurfaces.clear();
+ mReparentedSurfaces.clear();
+ if (mNativeObject != 0) {
+ nativeClearTransaction(mNativeObject);
+ }
+ }
+
+ /**
* Release the native transaction object, without applying it.
*/
@Override
@@ -3411,10 +3425,14 @@ public final class SurfaceControl implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
if (mNativeObject == 0) {
dest.writeInt(0);
- } else {
- dest.writeInt(1);
+ return;
}
+
+ dest.writeInt(1);
nativeWriteTransactionToParcel(mNativeObject, dest);
+ if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+ nativeClearTransaction(mNativeObject);
+ }
}
private void readFromParcel(Parcel in) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8c9c6bd8feeb..76eb882b6f53 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1200,7 +1200,8 @@ public final class ViewRootImpl implements ViewParent,
Looper.myLooper());
if (mAttachInfo.mThreadedRenderer != null) {
- InputMetricsListener listener = new InputMetricsListener();
+ InputMetricsListener listener =
+ new InputMetricsListener(mInputEventReceiver);
mHardwareRendererObserver = new HardwareRendererObserver(
listener, listener.data, mHandler, true /*waitForPresentTime*/);
mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
@@ -1396,9 +1397,6 @@ public final class ViewRootImpl implements ViewParent,
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;
- if (mHardwareRendererObserver != null) {
- mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
- }
}
}
}
@@ -3908,7 +3906,10 @@ public final class ViewRootImpl implements ViewParent,
mDrawsNeededToReport = 0;
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
} catch (RemoteException e) {
- // Have fun!
+ Log.e(mTag, "Unable to report draw finished", e);
+ mSurfaceChangedTransaction.apply();
+ } finally {
+ mSurfaceChangedTransaction.clear();
}
}
@@ -8083,9 +8084,6 @@ public final class ViewRootImpl implements ViewParent,
ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
if (hardwareRenderer != null) {
- if (mHardwareRendererObserver != null) {
- hardwareRenderer.removeObserver(mHardwareRendererObserver);
- }
if (mView != null) {
hardwareRenderer.destroyHardwareResources(mView);
}
@@ -8587,12 +8585,18 @@ public final class ViewRootImpl implements ViewParent,
super.dispose();
}
}
- private WindowInputEventReceiver mInputEventReceiver;
+ WindowInputEventReceiver mInputEventReceiver;
final class InputMetricsListener
implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
+ private InputEventReceiver mReceiver;
+
+ InputMetricsListener(InputEventReceiver receiver) {
+ mReceiver = receiver;
+ }
+
@Override
public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
@@ -8605,11 +8609,6 @@ public final class ViewRootImpl implements ViewParent,
// available, we cannot compute end-to-end input latency metrics.
return;
}
- final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
- if (mInputEventReceiver == null) {
- return;
- }
- mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
}
}
HardwareRendererObserver mHardwareRendererObserver;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6edd07178ed3..616910ab09ca 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2230,9 +2230,7 @@ public final class InputMethodManager {
public void removeImeSurface(IBinder windowToken) {
synchronized (mH) {
try {
- final Completable.Void value = Completable.createVoid();
- mService.removeImeSurfaceFromWindow(windowToken, ResultCallbacks.of(value));
- Completable.getResult(value);
+ mService.removeImeSurfaceFromWindowAsync(windowToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index db8801150f0d..90667cf54f93 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -86,7 +86,8 @@ public abstract class TextClassifierEvent implements Parcelable {
TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION,
TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION,
TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL,
- TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED, TYPE_LINKS_GENERATED})
+ TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED, TYPE_LINKS_GENERATED,
+ TYPE_READ_CLIPBOARD})
public @interface Type {
// For custom event types, use range 1,000,000+.
}
@@ -135,6 +136,13 @@ public abstract class TextClassifierEvent implements Parcelable {
public static final int TYPE_ACTIONS_GENERATED = 20;
/** Some text links were generated.*/
public static final int TYPE_LINKS_GENERATED = 21;
+ /**
+ * Read a clipboard.
+ * TODO: Make this public.
+ *
+ * @hide
+ */
+ public static final int TYPE_READ_CLIPBOARD = 22;
@Category
private final int mEventCategory;
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index f4fdf35fb50f..c09e8bde7417 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -302,6 +302,11 @@ public class UiTranslationController {
}
final LongSparseArray<ViewTranslationResponse> virtualChildResponse =
translatedResult.valueAt(i);
+ if (DEBUG) {
+ // TODO(b/182433547): remove before S release
+ Log.v(TAG, "onVirtualViewTranslationCompleted: receive "
+ + virtualChildResponse + " for AutofillId " + autofillId);
+ }
mActivity.runOnUiThread(() -> {
if (view.getViewTranslationCallback() == null) {
if (DEBUG) {
@@ -341,8 +346,13 @@ public class UiTranslationController {
}
for (int i = 0; i < resultCount; i++) {
final ViewTranslationResponse response = translatedResult.valueAt(i);
+ if (DEBUG) {
+ // TODO(b/182433547): remove before S release
+ Log.v(TAG, "onTranslationCompleted: response= " + response);
+ }
final AutofillId autofillId = response.getAutofillId();
if (autofillId == null) {
+ Log.w(TAG, "No AutofillId is set in ViewTranslationResponse:" + response);
continue;
}
final View view = mViews.get(autofillId).get();
@@ -394,6 +404,9 @@ public class UiTranslationController {
final TranslationRequest request = new TranslationRequest.Builder()
.setViewTranslationRequests(requests)
.build();
+ if (DEBUG) {
+ Log.d(TAG, "sendTranslationRequest: request= " + request);
+ }
translator.requestUiTranslate(request, (r) -> r.run(), this::onTranslationCompleted);
}
@@ -508,10 +521,17 @@ public class UiTranslationController {
private void runForEachView(BiConsumer<View, ViewTranslationCallback> action) {
synchronized (mLock) {
final ArrayMap<AutofillId, WeakReference<View>> views = new ArrayMap<>(mViews);
+ if (views.size() == 0) {
+ Log.w(TAG, "No views can be excuted for runForEachView.");
+ }
mActivity.runOnUiThread(() -> {
final int viewCounts = views.size();
for (int i = 0; i < viewCounts; i++) {
final View view = views.valueAt(i).get();
+ if (DEBUG) {
+ // TODO(b/182433547): remove before S release
+ Log.d(TAG, "runForEachView: view= " + view);
+ }
if (view == null || view.getViewTranslationCallback() == null) {
if (DEBUG) {
Log.d(TAG, "View was gone or ViewTranslationCallback for autofillid "
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index cd91d0266c75..95a3dc788803 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -104,25 +104,31 @@ public class EdgeEffect {
/**
* The velocity threshold before the spring animation is considered settled.
- * The idea here is that velocity should be less than 1 pixel per frame (~16ms).
+ * The idea here is that velocity should be less than 0.1 pixel per second.
*/
- private static final double VELOCITY_THRESHOLD = 1.0 / 0.016;
+ private static final double VELOCITY_THRESHOLD = 0.1;
/**
* The value threshold before the spring animation is considered close enough to
- * the destination to be settled. This should be around 1 pixel.
+ * the destination to be settled. This should be around 0.01 pixel.
*/
- private static final double VALUE_THRESHOLD = 1;
+ private static final double VALUE_THRESHOLD = 0.01;
/**
* The natural frequency of the stretch spring.
*/
- private static final double NATURAL_FREQUENCY = 17.55;
+ private static final double NATURAL_FREQUENCY = 24.657;
/**
* The damping ratio of the stretch spring.
*/
- private static final double DAMPING_RATIO = 0.92;
+ private static final double DAMPING_RATIO = 0.98;
+
+ /**
+ * The variation of the velocity for the stretch effect when it meets the bound.
+ * if value is > 1, it will accentuate the absorption of the movement.
+ */
+ private static final float ON_ABSORB_VELOCITY_ADJUSTMENT = 13f;
/** @hide */
@IntDef({TYPE_GLOW, TYPE_STRETCH})
@@ -460,7 +466,7 @@ public class EdgeEffect {
public void onAbsorb(int velocity) {
if (mEdgeEffectType == TYPE_STRETCH) {
mState = STATE_RECEDE;
- mVelocity = velocity;
+ mVelocity = velocity * ON_ABSORB_VELOCITY_ADJUSTMENT;
mDistance = 0;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
} else {
@@ -782,8 +788,8 @@ public class EdgeEffect {
* considered at rest or false if it is still animating.
*/
private boolean isAtEquilibrium() {
- double displacement = mDistance * mHeight * LINEAR_STRETCH_INTENSITY; // in pixels
- double velocity = mVelocity * LINEAR_STRETCH_INTENSITY;
+ double displacement = mDistance * mHeight; // in pixels
+ double velocity = mVelocity;
return Math.abs(velocity) < VELOCITY_THRESHOLD
&& Math.abs(displacement) < VALUE_THRESHOLD;
}
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 296d93c88554..a479b8ac4760 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -17,6 +17,7 @@
package android.widget;
import android.annotation.NonNull;
+import android.os.Build;
import android.text.method.TranslationTransformationMethod;
import android.util.Log;
import android.view.View;
@@ -34,7 +35,10 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
private static final String TAG = "TextViewTranslationCallback";
- private static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG);
+ // TODO(b/182433547): remove Build.IS_DEBUGGABLE before ship. Enable the logging in debug build
+ // to help the debug during the development phase
+ private static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)
+ || Build.IS_DEBUGGABLE;
private TranslationTransformationMethod mTranslationTransformation;
diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java
index 88584f4b2571..d84f571931fd 100644
--- a/core/java/android/window/WindowContextController.java
+++ b/core/java/android/window/WindowContextController.java
@@ -105,6 +105,7 @@ public class WindowContextController {
* a {@link com.android.server.wm.DisplayArea} by
* {@link #attachToDisplayArea(int, int, Bundle)}.
*
+ * @see WindowProviderService#attachToWindowToken(IBinder))
* @see IWindowManager#attachWindowContextToWindowToken(IBinder, IBinder)
*/
public void attachToWindowToken(IBinder windowToken) {
diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java
new file mode 100644
index 000000000000..b8619fbcf334
--- /dev/null
+++ b/core/java/android/window/WindowProviderService.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.annotation.UiContext;
+import android.app.ActivityThread;
+import android.app.LoadedApk;
+import android.app.Service;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.Display;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams.WindowType;
+import android.view.WindowManagerImpl;
+
+// TODO(b/159767464): handle #onConfigurationChanged(Configuration)
+/**
+ * A {@link Service} responsible for showing a non-activity window, such as software keyboards or
+ * accessibility overlay windows. This {@link Service} has similar behavior to
+ * {@link WindowContext}, but is represented as {@link Service}.
+ *
+ * @see android.inputmethodservice.InputMethodService
+ * @see android.accessibilityservice.AccessibilityService
+ *
+ * @hide
+ */
+@TestApi
+@UiContext
+public abstract class WindowProviderService extends Service {
+
+ private final WindowTokenClient mWindowToken = new WindowTokenClient();
+ private final WindowContextController mController = new WindowContextController(mWindowToken);
+ private WindowManager mWindowManager;
+
+ /**
+ * Returns the type of this {@link WindowProviderService}.
+ * Each inheriting class must implement this method to provide the type of the window. It is
+ * used similar to {@code type} of {@link Context#createWindowContext(int, Bundle)}
+ *
+ * @see Context#createWindowContext(int, Bundle)
+ *
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("OnNameExpected")
+ // Suppress the lint because it is not a callback and users should provide window type
+ // so we cannot make it final.
+ public abstract @WindowType int getWindowType();
+
+ /**
+ * Returns the option of this {@link WindowProviderService}.
+ * Default is {@code null}. The inheriting class can implement this method to provide the
+ * customization {@code option} of the window. It is used similar to {@code options} of
+ * {@link Context#createWindowContext(int, Bundle)}
+ *
+ * @see Context#createWindowContext(int, Bundle)
+ *
+ * @hide
+ */
+ @TestApi
+ @SuppressLint({"OnNameExpected", "NullableCollection"})
+ // Suppress the lint because it is not a callback and users may override this API to provide
+ // launch option. Also, the return value of this API is null by default.
+ @Nullable
+ public Bundle getWindowContextOptions() {
+ return null;
+ }
+
+ /**
+ * Attaches this WindowProviderService to the {@code windowToken}.
+ *
+ * @hide
+ */
+ @TestApi
+ public final void attachToWindowToken(@NonNull IBinder windowToken) {
+ mController.attachToWindowToken(windowToken);
+ }
+
+ /** @hide */
+ @Override
+ public final Context createServiceBaseContext(ActivityThread mainThread,
+ LoadedApk packageInfo) {
+ final Context context = super.createServiceBaseContext(mainThread, packageInfo);
+ // Always associate with the default display at initialization.
+ final Display defaultDisplay = context.getSystemService(DisplayManager.class)
+ .getDisplay(DEFAULT_DISPLAY);
+ return context.createTokenContext(mWindowToken, defaultDisplay);
+ }
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mWindowToken.attachContext(this);
+ mController.attachToDisplayArea(getWindowType(), getDisplayId(), getWindowContextOptions());
+ mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this);
+ }
+
+ @SuppressLint("OnNameExpected")
+ @Override
+ // Suppress the lint because ths is overridden from Context.
+ public @Nullable Object getSystemService(@NonNull String name) {
+ if (WINDOW_SERVICE.equals(name)) {
+ return mWindowManager;
+ }
+ return super.getSystemService(name);
+ }
+
+ @CallSuper
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mController.detachIfNeeded();
+ }
+}
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 86f29a8f07ef..84354d90b5f3 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -27,8 +27,12 @@ import android.annotation.Nullable;
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.KeyguardManager;
+import android.app.usage.UsageStatsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -64,9 +68,26 @@ public class SuspendedAppActivity extends AlertActivity
private int mNeutralButtonAction;
private int mUserId;
private PackageManager mPm;
+ private UsageStatsManager mUsm;
private Resources mSuspendingAppResources;
private SuspendDialogInfo mSuppliedDialogInfo;
private Bundle mOptions;
+ private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) {
+ final String[] unsuspended = intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) {
+ if (!isFinishing()) {
+ Slog.w(TAG, "Package " + mSuspendedPackage
+ + " got unsuspended while the dialog was visible. Finishing.");
+ SuspendedAppActivity.this.finish();
+ }
+ }
+ }
+ }
+ };
private CharSequence getAppLabel(String packageName) {
try {
@@ -183,6 +204,7 @@ public class SuspendedAppActivity extends AlertActivity
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPm = getPackageManager();
+ mUsm = getSystemService(UsageStatsManager.class);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
final Intent intent = getIntent();
@@ -222,6 +244,16 @@ public class SuspendedAppActivity extends AlertActivity
requestDismissKeyguardIfNeeded(ap.mMessage);
setupAlert();
+
+ final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null,
+ null);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mUnsuspendReceiver);
}
private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {
@@ -292,6 +324,7 @@ public class SuspendedAppActivity extends AlertActivity
}
break;
}
+ mUsm.reportUserInteraction(mSuspendingPackage, mUserId);
finish();
}
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index 2f4958223270..aa416c568dbc 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -52,8 +52,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {
measuredEnergyUC, mPowerEstimator, durationMs);
builder.getOrCreateSystemBatteryConsumerBuilder(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah, powerModel)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs);
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah, powerModel)
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs);
}
/**
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ac72d290b8b2..cb1900f300c0 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -40,6 +40,7 @@ import android.net.INetworkStatsService;
import android.net.NetworkStats;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Binder;
@@ -160,7 +161,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 196;
+ static final int VERSION = 197;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -6947,6 +6948,22 @@ public class BatteryStatsImpl extends BatteryStats {
return mGlobalMeasuredEnergyStats.getAccumulatedCustomBucketCharges();
}
+ /**
+ * Returns the names of custom power components.
+ */
+ public @NonNull String[] getCustomPowerComponentNames() {
+ if (mGlobalMeasuredEnergyStats == null) {
+ return new String[0];
+ }
+ final String[] names = mGlobalMeasuredEnergyStats.getCustomBucketNames();
+ for (int i = 0; i < names.length; i++) {
+ if (TextUtils.isEmpty(names[i])) {
+ names[i] = "CUSTOM_" + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + i;
+ }
+ }
+ return names;
+ }
+
@Override public long getStartClockTime() {
final long currentTimeMs = System.currentTimeMillis();
if ((currentTimeMs > MILLISECONDS_IN_YEAR
@@ -14379,17 +14396,18 @@ public class BatteryStatsImpl extends BatteryStats {
mConstants.startObserving(context.getContentResolver());
registerUsbStateReceiver(context);
}
+
/**
* Initialize the measured charge stats data structures.
*
* @param supportedStandardBuckets boolean array indicating which {@link StandardPowerBucket}s
- * are currently supported.
- * If null, none are supported (regardless of numCustomBuckets).
- * @param numCustomBuckets number of custom (OTHER) EnergyConsumers on this device
+ * are currently supported. If null, none are supported
+ * (regardless of customBucketNames).
+ * @param customBucketNames names of custom (OTHER) EnergyConsumers on this device
*/
@GuardedBy("this")
public void initMeasuredEnergyStatsLocked(@Nullable boolean[] supportedStandardBuckets,
- int numCustomBuckets) {
+ String[] customBucketNames) {
boolean supportedBucketMismatch = false;
mScreenStateAtLastEnergyMeasurement = mScreenState;
@@ -14401,10 +14419,10 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
if (mGlobalMeasuredEnergyStats == null) {
mGlobalMeasuredEnergyStats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
} else {
supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
- supportedStandardBuckets, numCustomBuckets);
+ supportedStandardBuckets, customBucketNames);
}
if (supportedStandardBuckets[MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH]) {
@@ -14423,7 +14441,7 @@ public class BatteryStatsImpl extends BatteryStats {
if (supportedBucketMismatch) {
mGlobalMeasuredEnergyStats = supportedStandardBuckets == null
- ? null : new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ ? null : new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
// Supported power buckets changed since last boot.
// Existing data is no longer reliable.
resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime());
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 49c564b8a737..c3986c27e4ba 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -123,11 +123,7 @@ public class BatteryUsageStatsProvider {
final long realtimeUs = mStats.mClocks.elapsedRealtime() * 1000;
final long uptimeUs = mStats.mClocks.uptimeMillis() * 1000;
- final long[] customMeasuredChargesUC =
- mStats.getCustomConsumerMeasuredBatteryConsumptionUC();
- final int customPowerComponentCount = customMeasuredChargesUC != null
- ? customMeasuredChargesUC.length
- : 0;
+ final String[] customPowerComponentNames = mStats.getCustomPowerComponentNames();
// TODO(b/174186358): read extra time component number from configuration
final int customTimeComponentCount = 0;
@@ -136,7 +132,7 @@ public class BatteryUsageStatsProvider {
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
- customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ customPowerComponentNames, customTimeComponentCount, includePowerModels);
batteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime());
SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
diff --git a/core/java/com/android/internal/os/BinderLatencyObserver.java b/core/java/com/android/internal/os/BinderLatencyObserver.java
index 59cc66d79bce..4ca59be4877a 100644
--- a/core/java/com/android/internal/os/BinderLatencyObserver.java
+++ b/core/java/com/android/internal/os/BinderLatencyObserver.java
@@ -16,22 +16,37 @@
package com.android.internal.os;
+import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
+
import android.annotation.Nullable;
import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BinderInternal.CallSession;
+import com.android.internal.os.BinderLatencyProto.ApiStats;
+import com.android.internal.os.BinderLatencyProto.Dims;
+import com.android.internal.os.BinderLatencyProto.RepeatedApiStats;
+import com.android.internal.util.FrameworkStatsLog;
import java.util.Random;
/** Collects statistics about Binder call latency per calling API and method. */
public class BinderLatencyObserver {
private static final String TAG = "BinderLatencyObserver";
+ private static final int MAX_ATOM_SIZE_BYTES = 4064;
+ // Be conservative and leave 1K space for the last histogram so we don't go over the size limit.
+ private static final int LAST_HISTOGRAM_BUFFER_SIZE_BYTES = 1000;
+
+ // Latency observer parameters.
public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 10;
+ public static final int STATSD_PUSH_INTERVAL_MINUTES_DEFAULT = 360;
// Histogram buckets parameters.
public static final int BUCKET_COUNT_DEFAULT = 100;
@@ -50,20 +65,124 @@ public class BinderLatencyObserver {
private int mFirstBucketSize = FIRST_BUCKET_SIZE_DEFAULT;
private float mBucketScaleFactor = BUCKET_SCALE_FACTOR_DEFAULT;
+ private int mStatsdPushIntervalMinutes = STATSD_PUSH_INTERVAL_MINUTES_DEFAULT;
+
private final Random mRandom;
private BinderLatencyBuckets mLatencyBuckets;
+ private final Handler mLatencyObserverHandler;
+
+ private Runnable mLatencyObserverRunnable = new Runnable() {
+ @Override
+ public void run() {
+ // Schedule the next push.
+ noteLatencyDelayed();
+
+ ArrayMap<LatencyDims, int[]> histogramMap;
+ synchronized (mLock) {
+ // Copy the histograms map so we don't use the lock for longer than needed.
+ histogramMap = new ArrayMap<>(mLatencyHistograms);
+ mLatencyHistograms.clear();
+ }
+
+ BinderTransactionNameResolver resolver = new BinderTransactionNameResolver();
+ ProtoOutputStream proto = new ProtoOutputStream();
+ int histogramsWritten = 0;
+
+ for (LatencyDims dims : histogramMap.keySet()) {
+ // Start a new atom if the next histogram risks going over the atom size limit.
+ if (proto.getRawSize() + LAST_HISTOGRAM_BUFFER_SIZE_BYTES > getMaxAtomSizeBytes()) {
+ if (histogramsWritten > 0) {
+ writeAtomToStatsd(proto);
+ }
+ proto = new ProtoOutputStream();
+ histogramsWritten = 0;
+ }
+
+ String transactionName = resolver.getMethodName(
+ dims.getBinderClass(), dims.getTransactionCode());
+ fillApiStatsProto(proto, dims, transactionName, histogramMap.get(dims));
+ histogramsWritten++;
+ }
+ // Push the final atom.
+ if (histogramsWritten > 0) {
+ writeAtomToStatsd(proto);
+ }
+ }
+ };
+
+ private void fillApiStatsProto(
+ ProtoOutputStream proto, LatencyDims dims, String transactionName, int[] histogram) {
+ // Find the part of the histogram to write.
+ int firstNonEmptyBucket = 0;
+ for (int i = 0; i < mBucketCount; i++) {
+ if (histogram[i] != 0) {
+ firstNonEmptyBucket = i;
+ break;
+ }
+ }
+ int lastNonEmptyBucket = mBucketCount - 1;
+ for (int i = mBucketCount - 1; i >= 0; i--) {
+ if (histogram[i] != 0) {
+ lastNonEmptyBucket = i;
+ break;
+ }
+ }
+
+ // Start a new ApiStats proto.
+ long apiStatsToken = proto.start(RepeatedApiStats.API_STATS);
+
+ // Write the dims.
+ long dimsToken = proto.start(ApiStats.DIMS);
+ proto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ proto.write(Dims.SERVICE_CLASS_NAME, dims.getBinderClass().getName());
+ proto.write(Dims.SERVICE_METHOD_NAME, transactionName);
+ proto.end(dimsToken);
+
+ // Write the histogram.
+ proto.write(ApiStats.FIRST_BUCKET_INDEX, firstNonEmptyBucket);
+ for (int i = firstNonEmptyBucket; i <= lastNonEmptyBucket; i++) {
+ proto.write(ApiStats.BUCKETS, histogram[i]);
+ }
+
+ proto.end(apiStatsToken);
+ }
+
+ protected int getMaxAtomSizeBytes() {
+ return MAX_ATOM_SIZE_BYTES;
+ }
+
+ protected void writeAtomToStatsd(ProtoOutputStream atom) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BINDER_LATENCY_REPORTED,
+ atom.getBytes(),
+ mPeriodicSamplingInterval,
+ 1);
+ }
+
+ private void noteLatencyDelayed() {
+ mLatencyObserverHandler.removeCallbacks(mLatencyObserverRunnable);
+ mLatencyObserverHandler.postDelayed(mLatencyObserverRunnable,
+ mStatsdPushIntervalMinutes * 60 * 1000);
+ }
+
/** Injector for {@link BinderLatencyObserver}. */
public static class Injector {
public Random getRandomGenerator() {
return new Random();
}
+
+ public Handler getHandler() {
+ return new Handler(Looper.getMainLooper());
+ }
}
public BinderLatencyObserver(Injector injector) {
mRandom = injector.getRandomGenerator();
+ mLatencyObserverHandler = injector.getHandler();
mLatencyBuckets = new BinderLatencyBuckets(
mBucketCount, mFirstBucketSize, mBucketScaleFactor);
+ noteLatencyDelayed();
}
/** Should be called when a Binder call completes, will store latency data. */
@@ -73,7 +192,8 @@ public class BinderLatencyObserver {
}
LatencyDims dims = new LatencyDims(s.binderClass, s.transactionCode);
- long callDuration = getElapsedRealtimeMicro() - s.timeStarted;
+ long elapsedTimeMicro = getElapsedRealtimeMicro();
+ long callDuration = elapsedTimeMicro - s.timeStarted;
// Find the bucket this sample should go to.
int bucketIdx = mLatencyBuckets.sampleToBucket(
@@ -117,6 +237,22 @@ public class BinderLatencyObserver {
}
}
+ /** Updates the statsd push interval. */
+ public void setPushInterval(int pushIntervalMinutes) {
+ if (pushIntervalMinutes <= 0) {
+ Slog.w(TAG, "Ignored invalid push interval (value must be positive): "
+ + pushIntervalMinutes);
+ return;
+ }
+
+ synchronized (mLock) {
+ if (pushIntervalMinutes != mStatsdPushIntervalMinutes) {
+ mStatsdPushIntervalMinutes = pushIntervalMinutes;
+ reset();
+ }
+ }
+ }
+
/** Updates the histogram buckets parameters. */
public void setHistogramBucketsParams(
int bucketCount, int firstBucketSize, float bucketScaleFactor) {
@@ -138,6 +274,7 @@ public class BinderLatencyObserver {
synchronized (mLock) {
mLatencyHistograms.clear();
}
+ noteLatencyDelayed();
}
/** Container for binder latency information. */
@@ -187,4 +324,9 @@ public class BinderLatencyObserver {
public ArrayMap<LatencyDims, int[]> getLatencyHistograms() {
return mLatencyHistograms;
}
+
+ @VisibleForTesting
+ public Runnable getStatsdPushRunnable() {
+ return mLatencyObserverRunnable;
+ }
}
diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java
index 4a4991bd3966..5cb54bd7fbc9 100644
--- a/core/java/com/android/internal/os/IdlePowerCalculator.java
+++ b/core/java/com/android/internal/os/IdlePowerCalculator.java
@@ -54,8 +54,8 @@ public class IdlePowerCalculator extends PowerCalculator {
BatteryStats.STATS_SINCE_CHARGED);
if (mPowerMah != 0) {
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_IDLE)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, mPowerMah)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, mDurationMs);
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE, mPowerMah)
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE, mDurationMs);
}
}
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
index 21dcce9fb64f..9ec40c6f6eed 100644
--- a/core/java/com/android/internal/os/MemoryPowerCalculator.java
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -32,8 +32,8 @@ public class MemoryPowerCalculator extends PowerCalculator {
final double powerMah = calculatePower(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_MEMORY)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah);
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY, durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY, powerMah);
}
@Override
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index 362ca0761b2c..6f279d99a5c9 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -45,8 +45,8 @@ public class PhonePowerCalculator extends PowerCalculator {
final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
if (phoneOnPower != 0) {
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_PHONE)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, phoneOnPower)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, phoneOnTimeMs);
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_PHONE, phoneOnTimeMs);
}
}
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 0267def918c2..0743c897a91f 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -96,9 +96,9 @@ public class ScreenPowerCalculator extends PowerCalculator {
}
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE,
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN,
totalPowerAndDuration.durationMs)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE,
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
Math.max(totalPowerAndDuration.powerMah, totalAppPower), powerModel)
.setPowerConsumedByApps(totalAppPower);
}
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 00a0627d068c..3153071fd75d 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -23,6 +23,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
+import android.text.TextUtils;
import android.util.DebugUtils;
import android.util.Slog;
import android.view.Display;
@@ -88,13 +89,15 @@ public class MeasuredEnergyStats {
*/
private final long[] mAccumulatedChargeMicroCoulomb;
+ private final String[] mCustomBucketNames;
+
/**
* Creates a MeasuredEnergyStats set to support the provided power buckets.
* supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_POWER_BUCKETS}.
* numCustomBuckets >= 0 is the number of (non-standard) custom power buckets on the device.
*/
- public MeasuredEnergyStats(boolean[] supportedStandardBuckets, int numCustomBuckets) {
- final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets;
+ public MeasuredEnergyStats(boolean[] supportedStandardBuckets, String[] customBucketNames) {
+ final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length;
mAccumulatedChargeMicroCoulomb = new long[numTotalBuckets];
// Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE.
// All custom buckets are, by definition, supported, so their values stay at 0.
@@ -103,6 +106,7 @@ public class MeasuredEnergyStats {
mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE;
}
}
+ mCustomBucketNames = customBucketNames;
}
/**
@@ -119,6 +123,7 @@ public class MeasuredEnergyStats {
mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE;
}
}
+ mCustomBucketNames = template.getCustomBucketNames();
}
/**
@@ -135,6 +140,7 @@ public class MeasuredEnergyStats {
*/
private MeasuredEnergyStats(int numIndices) {
mAccumulatedChargeMicroCoulomb = new long[numIndices];
+ mCustomBucketNames = new String[0];
}
/** Construct from parcel. */
@@ -142,12 +148,14 @@ public class MeasuredEnergyStats {
final int size = in.readInt();
mAccumulatedChargeMicroCoulomb = new long[size];
in.readLongArray(mAccumulatedChargeMicroCoulomb);
+ mCustomBucketNames = in.readStringArray();
}
/** Write to parcel */
public void writeToParcel(Parcel out) {
out.writeInt(mAccumulatedChargeMicroCoulomb.length);
out.writeLongArray(mAccumulatedChargeMicroCoulomb);
+ out.writeStringArray(mCustomBucketNames);
}
/**
@@ -294,7 +302,7 @@ public class MeasuredEnergyStats {
final int numCustomBuckets = arraySize - NUMBER_STANDARD_POWER_BUCKETS;
final MeasuredEnergyStats stats = new MeasuredEnergyStats(
- new boolean[NUMBER_STANDARD_POWER_BUCKETS], numCustomBuckets);
+ new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[numCustomBuckets]);
stats.readSummaryFromParcel(in, true);
return stats;
}
@@ -406,12 +414,12 @@ public class MeasuredEnergyStats {
/** Check if the supported power buckets are precisely those given. */
public boolean isSupportEqualTo(
- @NonNull boolean[] queriedStandardBuckets, int numCustomBuckets) {
+ @NonNull boolean[] queriedStandardBuckets, String[] customBucketNames) {
final int numBuckets = getNumberOfIndices();
// TODO(b/178504428): Detect whether custom buckets have changed qualitatively, not just
// quantitatively, and treat as mismatch if so.
- if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets) {
+ if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length) {
return false;
}
for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) {
@@ -422,6 +430,10 @@ public class MeasuredEnergyStats {
return true;
}
+ public String[] getCustomBucketNames() {
+ return mCustomBucketNames;
+ }
+
/** Dump debug data. */
public void dump(PrintWriter pw) {
pw.print(" ");
@@ -443,11 +455,16 @@ public class MeasuredEnergyStats {
* If the index is a standard bucket, returns its name; otherwise returns its prefixed custom
* bucket number.
*/
- private static String getBucketName(int index) {
+ private String getBucketName(int index) {
if (isValidStandardBucket(index)) {
return DebugUtils.valueToString(MeasuredEnergyStats.class, "POWER_BUCKET_", index);
}
- return "CUSTOM_" + indexToCustomBucket(index);
+ final int customBucket = indexToCustomBucket(index);
+ StringBuilder name = new StringBuilder().append("CUSTOM_").append(customBucket);
+ if (mCustomBucketNames != null && !TextUtils.isEmpty(mCustomBucketNames[customBucket])) {
+ name.append('(').append(mCustomBucketNames[customBucket]).append(')');
+ }
+ return name.toString();
}
/** Get the number of custom power buckets on this device. */
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 50bbfc5ccb08..fd13c26b05b2 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -89,8 +89,7 @@ interface IInputMethodManager {
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
oneway void removeImeSurface(in IVoidResultCallback resultCallback);
/** Remove the IME surface. Requires passing the currently focused window. */
- oneway void removeImeSurfaceFromWindow(in IBinder windowToken,
- in IVoidResultCallback resultCallback);
+ oneway void removeImeSurfaceFromWindowAsync(in IBinder windowToken);
oneway void startProtoDump(in byte[] protoDump, int source, String where,
in IVoidResultCallback resultCallback);
oneway void isImeTraceEnabled(in IBooleanResultCallback resultCallback);
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 8ecc80946141..bab4e93bdd9a 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -64,6 +64,7 @@ import com.android.internal.R;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
@@ -530,13 +531,7 @@ public class ConversationLayout extends FrameLayout
mConversationText.setText(conversationText);
// Update if the groups can hide the sender if they are first (applies to 1:1 conversations)
// This needs to happen after all of the above o update all of the groups
- for (int i = mGroups.size() - 1; i >= 0; i--) {
- MessagingGroup messagingGroup = mGroups.get(i);
- CharSequence messageSender = messagingGroup.getSenderName();
- boolean canHide = mIsOneToOne
- && TextUtils.equals(conversationText, messageSender);
- messagingGroup.setCanHideSenderIfFirst(canHide);
- }
+ mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText);
updateAppName();
updateIconPositionAndSize();
updateImageMessages();
@@ -779,35 +774,7 @@ public class ConversationLayout extends FrameLayout
private void updateTitleAndNamesDisplay() {
// Map of unique names to their prefix
- ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
- // Map of single-character string prefix to the only name which uses it, or null if multiple
- ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>();
- for (int i = 0; i < mGroups.size(); i++) {
- MessagingGroup group = mGroups.get(i);
- CharSequence senderName = group.getSenderName();
- if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
- continue;
- }
- if (!uniqueNames.containsKey(senderName)) {
- String charPrefix = mPeopleHelper.findNamePrefix(senderName, null);
- if (charPrefix == null) {
- continue;
- }
- if (uniqueCharacters.containsKey(charPrefix)) {
- // this character was already used, lets make it more unique. We first need to
- // resolve the existing character if it exists
- CharSequence existingName = uniqueCharacters.get(charPrefix);
- if (existingName != null) {
- uniqueNames.put(existingName, mPeopleHelper.findNameSplit(existingName));
- uniqueCharacters.put(charPrefix, null);
- }
- uniqueNames.put(senderName, mPeopleHelper.findNameSplit(senderName));
- } else {
- uniqueNames.put(senderName, charPrefix);
- uniqueCharacters.put(charPrefix, senderName);
- }
- }
- }
+ Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups);
// Now that we have the correct symbols, let's look what we have cached
ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a0e50be93410..db4e6734c848 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -933,19 +933,6 @@ public class LockPatternUtils {
}
/**
- * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
- * Not the most secure, but it is at least a second level of protection. First level is that
- * the file is in a location only readable by the system process.
- *
- * @param password the gesture pattern.
- *
- * @return the hash of the pattern in a byte array.
- */
- public String legacyPasswordToHash(byte[] password, int userId) {
- return LockscreenCredential.legacyPasswordToHash(password, getSalt(userId).getBytes());
- }
-
- /**
* Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
* {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
* {@link #CREDENTIAL_TYPE_PASSWORD}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index f5df3abad658..940979d7cd1f 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -16,15 +16,41 @@
package com.android.internal.widget;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.admin.PasswordMetrics;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* LockSettingsService local system service interface.
*
* @hide Only for use within the system server.
*/
public abstract class LockSettingsInternal {
+ /** ErrorCode for armRebootEscrow failures. **/
+ @IntDef(prefix = {"ARM_REBOOT_ERROR_"}, value = {
+ ARM_REBOOT_ERROR_NONE,
+ ARM_REBOOT_ERROR_UNSPECIFIED,
+ ARM_REBOOT_ERROR_ESCROW_NOT_READY,
+ ARM_REBOOT_ERROR_NO_PROVIDER,
+ ARM_REBOOT_ERROR_PROVIDER_MISMATCH,
+ ARM_REBOOT_ERROR_NO_ESCROW_KEY,
+ ARM_REBOOT_ERROR_KEYSTORE_FAILURE,
+ ARM_REBOOT_ERROR_STORE_ESCROW_KEY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ArmRebootEscrowErrorCode {}
+
+ public static final int ARM_REBOOT_ERROR_NONE = 0;
+ public static final int ARM_REBOOT_ERROR_UNSPECIFIED = 1;
+ public static final int ARM_REBOOT_ERROR_ESCROW_NOT_READY = 2;
+ public static final int ARM_REBOOT_ERROR_NO_PROVIDER = 3;
+ public static final int ARM_REBOOT_ERROR_PROVIDER_MISMATCH = 4;
+ public static final int ARM_REBOOT_ERROR_NO_ESCROW_KEY = 5;
+ public static final int ARM_REBOOT_ERROR_KEYSTORE_FAILURE = 6;
+ public static final int ARM_REBOOT_ERROR_STORE_ESCROW_KEY = 7;
+ // TODO(b/183140900) split store escrow key errors into detailed ones.
/**
* Create an escrow token for the current user, which can later be used to unlock FBE
@@ -104,9 +130,9 @@ public abstract class LockSettingsInternal {
* Should be called immediately before rebooting for an update. This depends on {@link
* #prepareRebootEscrow()} having been called and the escrow completing.
*
- * @return true if the arming worked
+ * @return ARM_ERROR_NONE if the arming worked
*/
- public abstract boolean armRebootEscrow();
+ public abstract @ArmRebootEscrowErrorCode int armRebootEscrow();
/**
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index f312d1d4f25d..f30b8442dc35 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -24,6 +24,7 @@ import android.annotation.StyleRes;
import android.app.Person;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
@@ -109,7 +110,10 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
private boolean mIsInConversation = true;
private ViewGroup mMessagingIconContainer;
private int mConversationContentStart;
- private int mNonConversationMarginEnd;
+ private int mNonConversationContentStart;
+ private int mNonConversationPaddingStart;
+ private int mConversationAvatarSize;
+ private int mNonConversationAvatarSize;
private int mNotificationTextMarginTop;
public MessagingGroup(@NonNull Context context) {
@@ -141,16 +145,21 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
mMessagingIconContainer = findViewById(R.id.message_icon_container);
mContentContainer = findViewById(R.id.messaging_group_content_container);
mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container);
- DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+ Resources res = getResources();
+ DisplayMetrics displayMetrics = res.getDisplayMetrics();
mDisplaySize.x = displayMetrics.widthPixels;
mDisplaySize.y = displayMetrics.heightPixels;
- mSenderTextPaddingSingleLine = getResources().getDimensionPixelSize(
+ mSenderTextPaddingSingleLine = res.getDimensionPixelSize(
R.dimen.messaging_group_singleline_sender_padding_end);
- mConversationContentStart = getResources().getDimensionPixelSize(
- R.dimen.conversation_content_start);
- mNonConversationMarginEnd = getResources().getDimensionPixelSize(
- R.dimen.messaging_layout_margin_end);
- mNotificationTextMarginTop = getResources().getDimensionPixelSize(
+ mConversationContentStart = res.getDimensionPixelSize(R.dimen.conversation_content_start);
+ mNonConversationContentStart = res.getDimensionPixelSize(
+ R.dimen.notification_content_margin_start);
+ mNonConversationPaddingStart = res.getDimensionPixelSize(
+ R.dimen.messaging_layout_icon_padding_start);
+ mConversationAvatarSize = res.getDimensionPixelSize(R.dimen.messaging_avatar_size);
+ mNonConversationAvatarSize = res.getDimensionPixelSize(
+ R.dimen.notification_icon_circle_size);
+ mNotificationTextMarginTop = res.getDimensionPixelSize(
R.dimen.notification_text_margin_top);
}
@@ -696,10 +705,18 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
mIsInConversation = isInConversation;
MarginLayoutParams layoutParams =
(MarginLayoutParams) mMessagingIconContainer.getLayoutParams();
- layoutParams.width = mIsInConversation ? mConversationContentStart
- : ViewPager.LayoutParams.WRAP_CONTENT;
- layoutParams.setMarginEnd(mIsInConversation ? 0 : mNonConversationMarginEnd);
+ layoutParams.width = mIsInConversation
+ ? mConversationContentStart
+ : mNonConversationContentStart;
mMessagingIconContainer.setLayoutParams(layoutParams);
+ int imagePaddingStart = isInConversation ? 0 : mNonConversationPaddingStart;
+ mMessagingIconContainer.setPaddingRelative(imagePaddingStart, 0, 0, 0);
+
+ ViewGroup.LayoutParams avatarLayoutParams = mAvatarView.getLayoutParams();
+ int size = mIsInConversation ? mConversationAvatarSize : mNonConversationAvatarSize;
+ avatarLayoutParams.height = size;
+ avatarLayoutParams.width = size;
+ mAvatarView.setLayoutParams(avatarLayoutParams);
}
}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 27cd6e13d86c..e1602a981920 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_AT_END;
+import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_EXTERNAL;
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_INLINE;
import android.annotation.AttrRes;
@@ -27,10 +27,6 @@ import android.app.Notification;
import android.app.Person;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -40,21 +36,22 @@ import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.RemoteViews;
-import android.widget.TextView;
import com.android.internal.R;
-import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.ContrastColorUtil;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.function.Consumer;
-import java.util.regex.Pattern;
/**
* A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
@@ -65,15 +62,6 @@ public class MessagingLayout extends FrameLayout
implements ImageMessageConsumer, IMessagingLayout {
private static final float COLOR_SHIFT_AMOUNT = 60;
- /**
- * Pattren for filter some ingonable characters.
- * p{Z} for any kind of whitespace or invisible separator.
- * p{C} for any kind of punctuation character.
- */
- private static final Pattern IGNORABLE_CHAR_PATTERN
- = Pattern.compile("[\\p{C}\\p{Z}]");
- private static final Pattern SPECIAL_CHAR_PATTERN
- = Pattern.compile ("[!@#$%&*()_+=|<>?{}\\[\\]~-]");
private static final Consumer<MessagingMessage> REMOVE_MESSAGE
= MessagingMessage::removeMessage;
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
@@ -81,26 +69,26 @@ public class MessagingLayout extends FrameLayout
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
= new MessagingPropertyAnimator();
+ private final PeopleHelper mPeopleHelper = new PeopleHelper();
private List<MessagingMessage> mMessages = new ArrayList<>();
private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
private MessagingLinearLayout mMessagingLinearLayout;
private boolean mShowHistoricMessages;
private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
- private TextView mTitleView;
+ private MessagingLinearLayout mImageMessageContainer;
+ private ImageView mRightIconView;
+ private Rect mMessagingClipRect;
private int mLayoutColor;
private int mSenderTextColor;
private int mMessageTextColor;
- private int mAvatarSize;
- private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private Paint mTextPaint = new Paint();
- private CharSequence mConversationTitle;
private Icon mAvatarReplacement;
private boolean mIsOneToOne;
private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
private Person mUser;
private CharSequence mNameReplacement;
- private boolean mDisplayImagesAtEnd;
+ private boolean mIsCollapsed;
private ImageResolver mImageResolver;
+ private CharSequence mConversationTitle;
public MessagingLayout(@NonNull Context context) {
super(context);
@@ -123,17 +111,16 @@ public class MessagingLayout extends FrameLayout
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mPeopleHelper.init(getContext());
mMessagingLinearLayout = findViewById(R.id.notification_messaging);
+ mImageMessageContainer = findViewById(R.id.conversation_image_message_container);
+ mRightIconView = findViewById(R.id.right_icon);
// We still want to clip, but only on the top, since views can temporarily out of bounds
// during transitions.
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int size = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
- Rect rect = new Rect(0, 0, size, size);
- mMessagingLinearLayout.setClipBounds(rect);
- mTitleView = findViewById(R.id.title);
- mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
- mTextPaint.setAntiAlias(true);
+ mMessagingClipRect = new Rect(0, 0, size, size);
+ setMessagingClippingDisabled(false);
}
@RemotableViewMethod
@@ -153,7 +140,7 @@ public class MessagingLayout extends FrameLayout
*/
@RemotableViewMethod
public void setIsCollapsed(boolean isCollapsed) {
- mDisplayImagesAtEnd = isCollapsed;
+ mIsCollapsed = isCollapsed;
}
@RemotableViewMethod
@@ -168,7 +155,7 @@ public class MessagingLayout extends FrameLayout
*/
@RemotableViewMethod
public void setConversationTitle(CharSequence conversationTitle) {
- // Unused
+ mConversationTitle = conversationTitle;
}
@RemotableViewMethod
@@ -180,11 +167,6 @@ public class MessagingLayout extends FrameLayout
List<Notification.MessagingStyle.Message> newHistoricMessages
= Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
- mConversationTitle = null;
- TextView headerText = findViewById(R.id.header_text);
- if (headerText != null) {
- mConversationTitle = headerText.getText();
- }
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
addRemoteInputHistoryToMessages(newMessages, history);
@@ -238,6 +220,41 @@ public class MessagingLayout extends FrameLayout
updateHistoricMessageVisibility();
updateTitleAndNamesDisplay();
+ // after groups are finalized, hide the first sender name if it's showing as the title
+ mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, mConversationTitle);
+ updateImageMessages();
+ }
+
+ private void updateImageMessages() {
+ View newMessage = null;
+ if (mImageMessageContainer == null) {
+ return;
+ }
+ if (mIsCollapsed && !mGroups.isEmpty()) {
+ // When collapsed, we're displaying the image message in a dedicated container
+ // on the right of the layout instead of inline. Let's add the isolated image there
+ MessagingGroup messagingGroup = mGroups.get(mGroups.size() - 1);
+ MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage();
+ if (isolatedMessage != null) {
+ newMessage = isolatedMessage.getView();
+ }
+ }
+ // Remove all messages that don't belong into the image layout
+ View previousMessage = mImageMessageContainer.getChildAt(0);
+ if (previousMessage != newMessage) {
+ mImageMessageContainer.removeView(previousMessage);
+ if (newMessage != null) {
+ mImageMessageContainer.addView(newMessage);
+ }
+ }
+ mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE);
+
+ // When showing an image message, do not show the large icon. Removing the drawable
+ // prevents it from being shown in the left_icon view (by the grouping util).
+ if (newMessage != null && mRightIconView != null && mRightIconView.getDrawable() != null) {
+ mRightIconView.setImageDrawable(null);
+ mRightIconView.setVisibility(GONE);
+ }
}
private void removeGroups(ArrayList<MessagingGroup> oldGroups) {
@@ -266,34 +283,7 @@ public class MessagingLayout extends FrameLayout
}
private void updateTitleAndNamesDisplay() {
- ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
- ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
- for (int i = 0; i < mGroups.size(); i++) {
- MessagingGroup group = mGroups.get(i);
- CharSequence senderName = group.getSenderName();
- if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
- continue;
- }
- if (!uniqueNames.containsKey(senderName)) {
- // Only use visible characters to get uniqueNames
- String pureSenderName = IGNORABLE_CHAR_PATTERN
- .matcher(senderName).replaceAll("" /* replacement */);
- char c = pureSenderName.charAt(0);
- if (uniqueCharacters.containsKey(c)) {
- // this character was already used, lets make it more unique. We first need to
- // resolve the existing character if it exists
- CharSequence existingName = uniqueCharacters.get(c);
- if (existingName != null) {
- uniqueNames.put(existingName, findNameSplit((String) existingName));
- uniqueCharacters.put(c, null);
- }
- uniqueNames.put(senderName, findNameSplit((String) senderName));
- } else {
- uniqueNames.put(senderName, Character.toString(c));
- uniqueCharacters.put(c, pureSenderName);
- }
- }
- }
+ Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups);
// Now that we have the correct symbols, let's look what we have cached
ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
@@ -337,26 +327,7 @@ public class MessagingLayout extends FrameLayout
}
public Icon createAvatarSymbol(CharSequence senderName, String symbol, int layoutColor) {
- if (symbol.isEmpty() || TextUtils.isDigitsOnly(symbol) ||
- SPECIAL_CHAR_PATTERN.matcher(symbol).find()) {
- Icon avatarIcon = Icon.createWithResource(getContext(),
- com.android.internal.R.drawable.messaging_user);
- avatarIcon.setTint(findColor(senderName, layoutColor));
- return avatarIcon;
- } else {
- Bitmap bitmap = Bitmap.createBitmap(mAvatarSize, mAvatarSize, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- float radius = mAvatarSize / 2.0f;
- int color = findColor(senderName, layoutColor);
- mPaint.setColor(color);
- canvas.drawCircle(radius, radius, radius, mPaint);
- boolean needDarkText = ColorUtils.calculateLuminance(color) > 0.5f;
- mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE);
- mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.5f : mAvatarSize * 0.3f);
- int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2));
- canvas.drawText(symbol, radius, yPos, mTextPaint);
- return Icon.createWithBitmap(bitmap);
- }
+ return mPeopleHelper.createAvatarSymbol(senderName, symbol, layoutColor);
}
private int findColor(CharSequence senderName, int layoutColor) {
@@ -449,8 +420,8 @@ public class MessagingLayout extends FrameLayout
newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
mAddedGroups.add(newGroup);
}
- newGroup.setImageDisplayLocation(mDisplayImagesAtEnd
- ? IMAGE_DISPLAY_LOCATION_AT_END
+ newGroup.setImageDisplayLocation(mIsCollapsed
+ ? IMAGE_DISPLAY_LOCATION_EXTERNAL
: IMAGE_DISPLAY_LOCATION_INLINE);
newGroup.setIsInConversation(false);
newGroup.setLayoutColor(mLayoutColor);
@@ -460,6 +431,8 @@ public class MessagingLayout extends FrameLayout
if (sender != mUser && mNameReplacement != null) {
nameOverride = mNameReplacement;
}
+ newGroup.setSingleLine(mIsCollapsed);
+ newGroup.setShowingAvatar(!mIsCollapsed);
newGroup.setSender(sender, nameOverride);
newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
mGroups.add(newGroup);
@@ -600,12 +573,17 @@ public class MessagingLayout extends FrameLayout
return mMessagingLinearLayout;
}
+ @Nullable
+ public ViewGroup getImageMessageContainer() {
+ return mImageMessageContainer;
+ }
+
public ArrayList<MessagingGroup> getMessagingGroups() {
return mGroups;
}
@Override
public void setMessagingClippingDisabled(boolean clippingDisabled) {
- // Don't do anything, this is only used for the ConversationLayout
+ mMessagingLinearLayout.setClipBounds(clippingDisabled ? null : mMessagingClipRect);
}
}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 7a8ead6b33f1..de3b6a4dacb2 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -165,15 +165,23 @@ public class NotificationExpandButton extends FrameLayout {
private void updateColors() {
if (shouldShowNumber() && !mDisallowColor) {
- mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
+ if (mHighlightPillColor != 0) {
+ mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
+ }
mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN);
mIconView.setColorFilter(mHighlightTextColor, PorterDuff.Mode.SRC_IN);
- mNumberView.setTextColor(mHighlightTextColor);
+ if (mHighlightTextColor != 0) {
+ mNumberView.setTextColor(mHighlightTextColor);
+ }
} else {
- mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
+ if (mDefaultPillColor != 0) {
+ mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
+ }
mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN);
mIconView.setColorFilter(mDefaultTextColor, PorterDuff.Mode.SRC_IN);
- mNumberView.setTextColor(mDefaultTextColor);
+ if (mDefaultTextColor != 0) {
+ mNumberView.setTextColor(mDefaultTextColor);
+ }
}
}
diff --git a/core/java/com/android/internal/widget/PeopleHelper.java b/core/java/com/android/internal/widget/PeopleHelper.java
index 77f4c8f6bede..85cedc362b99 100644
--- a/core/java/com/android/internal/widget/PeopleHelper.java
+++ b/core/java/com/android/internal/widget/PeopleHelper.java
@@ -21,6 +21,7 @@ import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT;
import android.annotation.ColorInt;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -28,12 +29,15 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.view.View;
import com.android.internal.R;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.ContrastColorUtil;
+import java.util.List;
+import java.util.Map;
import java.util.regex.Pattern;
/**
@@ -176,4 +180,58 @@ public class PeopleHelper {
}
return findNamePrefix(name, "");
}
+
+ /**
+ * Creates a mapping of the unique sender names in the groups to the string 1- or 2-character
+ * prefix strings for the names, which are extracted as the initials, and should be used for
+ * generating the avatar. Senders not requiring a generated avatar, or with an empty name are
+ * omitted.
+ */
+ public Map<CharSequence, String> mapUniqueNamesToPrefix(List<MessagingGroup> groups) {
+ // Map of unique names to their prefix
+ ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
+ // Map of single-character string prefix to the only name which uses it, or null if multiple
+ ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>();
+ for (int i = 0; i < groups.size(); i++) {
+ MessagingGroup group = groups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
+ continue;
+ }
+ if (!uniqueNames.containsKey(senderName)) {
+ String charPrefix = findNamePrefix(senderName, null);
+ if (charPrefix == null) {
+ continue;
+ }
+ if (uniqueCharacters.containsKey(charPrefix)) {
+ // this character was already used, lets make it more unique. We first need to
+ // resolve the existing character if it exists
+ CharSequence existingName = uniqueCharacters.get(charPrefix);
+ if (existingName != null) {
+ uniqueNames.put(existingName, findNameSplit(existingName));
+ uniqueCharacters.put(charPrefix, null);
+ }
+ uniqueNames.put(senderName, findNameSplit(senderName));
+ } else {
+ uniqueNames.put(senderName, charPrefix);
+ uniqueCharacters.put(charPrefix, senderName);
+ }
+ }
+ }
+ return uniqueNames;
+ }
+
+ /**
+ * Update whether the groups can hide the sender if they are first
+ * (happens only for 1:1 conversations where the given title matches the sender's name)
+ */
+ public void maybeHideFirstSenderName(@NonNull List<MessagingGroup> groups,
+ boolean isOneToOne, @Nullable CharSequence conversationTitle) {
+ for (int i = groups.size() - 1; i >= 0; i--) {
+ MessagingGroup messagingGroup = groups.get(i);
+ CharSequence messageSender = messagingGroup.getSenderName();
+ boolean canHide = isOneToOne && TextUtils.equals(conversationTitle, messageSender);
+ messagingGroup.setCanHideSenderIfFirst(canHide);
+ }
+ }
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b3427551ea7b..ffba628f73ab 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1562,6 +1562,13 @@ static void nativeWriteTransactionToParcel(JNIEnv* env, jclass clazz, jlong nati
reinterpret_cast<SurfaceComposerClient::Transaction *>(nativeObject);
if (self != nullptr) {
self->writeToParcel(parcel);
+ }
+}
+
+static void nativeClearTransaction(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ SurfaceComposerClient::Transaction* const self =
+ reinterpret_cast<SurfaceComposerClient::Transaction*>(nativeObject);
+ if (self != nullptr) {
self->clear();
}
}
@@ -1880,6 +1887,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeReadTransactionFromParcel },
{"nativeWriteTransactionToParcel", "(JLandroid/os/Parcel;)V",
(void*)nativeWriteTransactionToParcel },
+ {"nativeClearTransaction", "(J)V",
+ (void*)nativeClearTransaction },
{"nativeMirrorSurface", "(J)J",
(void*)nativeMirrorSurface },
{"nativeSetGlobalShadowSettings", "([F[FFFF)V",
diff --git a/core/proto/android/internal/binder_latency.proto b/core/proto/android/internal/binder_latency.proto
new file mode 100644
index 000000000000..e32c3e3441c5
--- /dev/null
+++ b/core/proto/android/internal/binder_latency.proto
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package com.android.internal.os;
+
+option java_outer_classname = "BinderLatencyProto";
+
+/**
+ * RepeatedApiStats proto from atoms.proto, duplicated here so that it's
+ * accessible in the build.
+ * Must be kept in sync with the version in atoms.proto.
+ */
+
+message RepeatedApiStats {
+ repeated ApiStats api_stats = 1;
+}
+
+message Dims {
+ enum ProcessSource {
+ UNKNOWN_PROCESS_SOURCE = 0;
+ SYSTEM_SERVER = 1;
+ TELEPHONY = 2;
+ }
+
+ enum ServiceClassName {
+ UNKNOWN_CLASS = 0;
+ }
+ enum ServiceMethodName {
+ UNKNOWN_METHOD = 0;
+ }
+
+ // Required.
+ optional ProcessSource process_source = 1;
+
+ // The class name of the API making the call to Binder. Enum value
+ // is preferred as uses much less data to store.
+ // This field does not contain PII.
+ oneof service_class {
+ ServiceClassName service_class_name_as_enum = 2;
+ string service_class_name = 3;
+ }
+
+ // Method name of the API call. It can also be a transaction code if we
+ // cannot resolve it to a name. See Binder#getTransactionName. Enum value
+ // is preferred as uses much less data to store.
+ // This field does not contain PII.
+ oneof service_method {
+ ServiceMethodName service_method_name_as_enum = 4;
+ string service_method_name = 5;
+ }
+}
+
+message ApiStats {
+ // required.
+ optional Dims dims = 1;
+
+ // Indicates the first bucket that had any data. Allows omitting any empty
+ // buckets at the start of the bucket list and thus save on data size.
+ optional int32 first_bucket_index = 2;
+ // Stores the count of samples for each bucket. The number of buckets and
+ // their sizes are controlled server side with a flag.
+ repeated int32 buckets = 3;
+} \ No newline at end of file
diff --git a/core/res/res/drawable/ic_call_answer_video.xml b/core/res/res/drawable/ic_call_answer_video.xml
new file mode 100644
index 000000000000..77c889234dd0
--- /dev/null
+++ b/core/res/res/drawable/ic_call_answer_video.xml
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20"
+ android:tint="?android:attr/colorControlNormal"
+ android:autoMirrored="true">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15,8v8H5V8h10m1,-2H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0
+ 1,-0.45 1,-1v-3.5l4,4v-11l-4,4V7c0,-0.55 -0.45,-1 -1,-1z"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/layout/notification_expand_button.xml b/core/res/res/layout/notification_expand_button.xml
index b969fa49bcc7..e752431ce75f 100644
--- a/core/res/res/layout/notification_expand_button.xml
+++ b/core/res/res/layout/notification_expand_button.xml
@@ -22,7 +22,6 @@
android:layout_gravity="top|end"
android:contentDescription="@string/expand_button_content_description_collapsed"
android:padding="16dp"
- android:visibility="gone"
>
<LinearLayout
@@ -40,6 +39,7 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
android:gravity="center_vertical"
android:paddingStart="8dp"
+ android:visibility="gone"
/>
<ImageView
diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml
index e01d8035fe35..389637eb2517 100644
--- a/core/res/res/layout/notification_template_conversation_header.xml
+++ b/core/res/res/layout/notification_template_conversation_header.xml
@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingTop="16dp"
+ android:paddingTop="20dp"
>
<TextView
@@ -42,8 +42,6 @@
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
- android:layout_gravity="center"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -54,10 +52,8 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -70,8 +66,6 @@
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
- android:layout_gravity="center"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -81,9 +75,7 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
- android:paddingTop="1sp"
android:showRelative="true"
android:singleLine="true"
android:visibility="gone"
@@ -93,7 +85,6 @@
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout="@layout/notification_template_part_chronometer"
android:visibility="gone"
@@ -107,8 +98,6 @@
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
- android:layout_gravity="center"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -117,9 +106,8 @@
android:id="@+id/verification_icon"
android:layout_width="@dimen/notification_verification_icon_size"
android:layout_height="@dimen/notification_verification_icon_size"
- android:layout_gravity="center"
android:layout_marginStart="4dp"
- android:paddingTop="2dp"
+ android:baseline="10dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_notifications_alerted"
android:visibility="gone"
@@ -130,9 +118,7 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
- android:paddingTop="1sp"
android:showRelative="true"
android:singleLine="true"
android:visibility="gone"
@@ -142,11 +128,10 @@
android:id="@+id/feedback"
android:layout_width="@dimen/notification_feedback_size"
android:layout_height="@dimen/notification_feedback_size"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_header_separating_margin"
android:background="?android:selectableItemBackgroundBorderless"
android:contentDescription="@string/notification_feedback_indicator"
- android:paddingTop="2dp"
+ android:baseline="13dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_feedback_indicator"
android:visibility="gone"
@@ -157,21 +142,19 @@
android:layout_width="@dimen/notification_phishing_alert_size"
android:layout_height="@dimen/notification_phishing_alert_size"
android:layout_marginStart="4dp"
- android:paddingTop="2dp"
+ android:baseline="10dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_dialog_alert_material"
android:visibility="gone"
android:contentDescription="@string/notification_phishing_alert_content_description"
/>
-
<ImageView
android:id="@+id/profile_badge"
android:layout_width="@dimen/notification_badge_size"
android:layout_height="@dimen/notification_badge_size"
- android:layout_gravity="center"
android:layout_marginStart="4dp"
- android:paddingTop="2dp"
+ android:baseline="10dp"
android:scaleType="fitCenter"
android:visibility="gone"
android:contentDescription="@string/notification_work_profile_content_description"
@@ -181,10 +164,9 @@
android:id="@+id/alerted_icon"
android:layout_width="@dimen/notification_alerted_size"
android:layout_height="@dimen/notification_alerted_size"
- android:layout_gravity="center"
android:layout_marginStart="4dp"
+ android:baseline="10dp"
android:contentDescription="@string/notification_alerted_content_description"
- android:paddingTop="2dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_notifications_alerted"
android:visibility="gone"
diff --git a/core/res/res/layout/notification_template_conversation_icon_container.xml b/core/res/res/layout/notification_template_conversation_icon_container.xml
index e9ec7ce77deb..a88ff0d104a6 100644
--- a/core/res/res/layout/notification_template_conversation_icon_container.xml
+++ b/core/res/res/layout/notification_template_conversation_icon_container.xml
@@ -23,8 +23,8 @@
android:gravity="start|top"
android:clipChildren="false"
android:clipToPadding="false"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
+ android:paddingTop="20dp"
+ android:paddingBottom="16dp"
android:importantForAccessibility="no"
>
diff --git a/core/res/res/layout/notification_template_material_big_messaging.xml b/core/res/res/layout/notification_template_material_big_messaging.xml
new file mode 100644
index 000000000000..01c37b7515e9
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_big_messaging.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<com.android.internal.widget.MessagingLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ android:tag="messaging"
+ >
+ <include layout="@layout/notification_template_header"/>
+ <com.android.internal.widget.RemeasuringLinearLayout
+ android:id="@+id/notification_action_list_margin_target"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:clipChildren="false"
+ android:orientation="vertical">
+
+ <com.android.internal.widget.RemeasuringLinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:layout_weight="1"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ >
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/notification_messaging"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:spacing="@dimen/notification_messaging_spacing" />
+ </com.android.internal.widget.RemeasuringLinearLayout>
+ <include layout="@layout/notification_template_smart_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_content_margin"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end" />
+ <include layout="@layout/notification_material_action_list" />
+ </com.android.internal.widget.RemeasuringLinearLayout>
+ <include layout="@layout/notification_template_right_icon" />
+</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_template_material_call.xml b/core/res/res/layout/notification_template_material_call.xml
index 5d9e761842d8..1b3bd2673a7a 100644
--- a/core/res/res/layout/notification_template_material_call.xml
+++ b/core/res/res/layout/notification_template_material_call.xml
@@ -29,7 +29,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="80dp"
+ android:layout_height="88dp"
android:orientation="horizontal"
>
diff --git a/core/res/res/layout/notification_template_material_heads_up_base.xml b/core/res/res/layout/notification_template_material_heads_up_base.xml
index d55499130dcc..a0d19b409cea 100644
--- a/core/res/res/layout/notification_template_material_heads_up_base.xml
+++ b/core/res/res/layout/notification_template_material_heads_up_base.xml
@@ -38,7 +38,7 @@
<com.android.internal.widget.RemeasuringLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="-12dp"
+ android:layout_marginTop="-20dp"
android:clipChildren="false"
android:orientation="vertical"
>
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index c3fd249d3ad5..3564f9755a5d 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -22,32 +22,186 @@
android:clipChildren="false"
android:tag="messaging"
>
- <include layout="@layout/notification_template_header"/>
- <com.android.internal.widget.RemeasuringLinearLayout
- android:id="@+id/notification_action_list_margin_target"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:clipToPadding="false"
- android:orientation="vertical">
- <com.android.internal.widget.RemeasuringLinearLayout
- android:id="@+id/notification_main_column"
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:orientation="vertical"
+ >
+
+
+ <com.android.internal.widget.NotificationMaxHeightFrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:orientation="vertical"
+ android:minHeight="@dimen/notification_min_height"
+ android:clipChildren="false"
>
- <com.android.internal.widget.MessagingLinearLayout
- android:id="@+id/notification_messaging"
+
+ <ImageView
+ android:id="@+id/left_icon"
+ android:layout_width="@dimen/notification_left_icon_size"
+ android:layout_height="@dimen/notification_left_icon_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_left_icon_start"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:visibility="gone"
+ />
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_icon_circle_size"
+ android:layout_height="@dimen/notification_icon_circle_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:padding="@dimen/notification_icon_circle_padding"
+ />
+
+ <FrameLayout
+ android:id="@+id/alternate_expand_target"
+ android:layout_width="@dimen/notification_content_margin_start"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:importantForAccessibility="no"
+ />
+
+ <!--
+ NOTE: to make the expansion animation of id/notification_messaging happen vertically,
+ its X positioning must be the left edge of the notification, so instead of putting the
+ layout_marginStart on the id/notification_headerless_view_row, we put it on
+ id/notification_top_line, making the layout here just a bit different from the base.
+ -->
+ <LinearLayout
+ android:id="@+id/notification_headerless_view_row"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:spacing="@dimen/notification_messaging_spacing" />
- </com.android.internal.widget.RemeasuringLinearLayout>
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ >
+
+ <!--
+ NOTE: because messaging will always have 2 lines, this LinearLayout should NOT
+ have the id/notification_headerless_view_column, as that is used for modifying
+ vertical margins to accommodate the single-line state that base supports
+ -->
+ <LinearLayout
+ android:layout_width="0px"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+ android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+ android:clipChildren="false"
+ android:orientation="vertical"
+ >
+
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:clipChildren="false"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ >
+
+ <!--
+ NOTE: The notification_top_line_views layout contains the app_name_text.
+ In order to include the title view at the beginning, the Notification.Builder
+ has logic to hide that view whenever this title view is to be visible.
+ -->
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+ />
+
+ <include layout="@layout/notification_top_line_views" />
+
+ </NotificationTopLineView>
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ >
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/notification_messaging"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:spacing="@dimen/notification_messaging_spacing" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <!-- Images -->
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/conversation_image_message_container"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+ android:forceHasOverlappingRendering="false"
+ android:spacing="0dp"
+ android:clipChildren="false"
+ android:visibility="gone"
+ />
+
+ <ImageView
+ android:id="@+id/right_icon"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ />
+
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+ </com.android.internal.widget.NotificationMaxHeightFrameLayout>
+
+ <LinearLayout
+ android:id="@+id/notification_action_list_margin_target"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-20dp"
+ android:clipChildren="false"
+ android:orientation="vertical">
<include layout="@layout/notification_template_smart_reply_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -55,6 +209,6 @@
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end" />
<include layout="@layout/notification_material_action_list" />
- </com.android.internal.widget.RemeasuringLinearLayout>
- <include layout="@layout/notification_template_right_icon" />
+ </LinearLayout>
+</LinearLayout>
</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_top_line_views.xml b/core/res/res/layout/notification_top_line_views.xml
index 88bcc4dc9e39..8284279be3a0 100644
--- a/core/res/res/layout/notification_top_line_views.xml
+++ b/core/res/res/layout/notification_top_line_views.xml
@@ -113,11 +113,10 @@
android:layout_width="@dimen/notification_feedback_size"
android:layout_height="@dimen/notification_feedback_size"
android:layout_marginStart="@dimen/notification_header_separating_margin"
- android:layout_gravity="center"
+ android:baseline="13dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_feedback_indicator"
android:background="?android:selectableItemBackgroundBorderless"
- android:paddingTop="2dp"
android:visibility="gone"
android:contentDescription="@string/notification_feedback_indicator"
/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 906a7403298f..419f142d0795 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1772,6 +1772,9 @@
<!-- Add algorithm here -->
</string-array>
+ <!-- Boolean indicating if placing the phone face down will result in a screen off. -->
+ <bool name="config_flipToScreenOffEnabled">true</bool>
+
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index fc2645c7c88b..0e436e36b474 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -758,23 +758,23 @@
<dimen name="notification_grayscale_icon_max_size">256dp</dimen>
<dimen name="messaging_avatar_size">36dp</dimen>
- <dimen name="conversation_avatar_size">52dp</dimen>
+ <dimen name="conversation_avatar_size">48dp</dimen>
<!-- start margin of the icon circle in the conversation's skin of the header -->
<dimen name="conversation_icon_circle_start">28dp</dimen>
<!-- Start of the content in the conversation template -->
<dimen name="conversation_content_start">80dp</dimen>
<!-- Height of the expand button in the conversation layout -->
- <dimen name="conversation_expand_button_height">80dp</dimen>
+ <dimen name="conversation_expand_button_height">88dp</dimen>
<!-- this is the margin between the Conversation image and the content -->
<dimen name="conversation_image_start_margin">12dp</dimen>
<!-- Side margins of the conversation badge in relation to the conversation icon -->
- <dimen name="conversation_badge_side_margin">36dp</dimen>
+ <dimen name="conversation_badge_side_margin">32dp</dimen>
<!-- size of the notification badge when applied to the conversation icon -->
<dimen name="conversation_icon_size_badged">20dp</dimen>
<!-- size of the conversation avatar in an expanded group -->
<dimen name="conversation_avatar_size_group_expanded">@dimen/messaging_avatar_size</dimen>
<!-- size of the face pile icons -->
- <dimen name="conversation_face_pile_avatar_size">@dimen/messaging_avatar_size</dimen>
+ <dimen name="conversation_face_pile_avatar_size">32dp</dimen>
<!-- size of the face pile icons when the group is expanded -->
<dimen name="conversation_face_pile_avatar_size_group_expanded">25dp</dimen>
<!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded-->
@@ -795,7 +795,7 @@
<dimen name="importance_ring_size">20dp</dimen>
<!-- The top padding of the conversation icon container in the regular state-->
- <dimen name="conversation_icon_container_top_padding">12dp</dimen>
+ <dimen name="conversation_icon_container_top_padding">20dp</dimen>
<!-- The top padding of the conversation icon container when the avatar is small-->
<dimen name="conversation_icon_container_top_padding_small_avatar">9dp</dimen>
@@ -803,8 +803,8 @@
<!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
<dimen name="conversation_header_expanded_padding_end">38dp</dimen>
- <!-- margin at the end of messaging group icons when not conversations -->
- <dimen name="messaging_layout_margin_end">12dp</dimen>
+ <!-- extra padding at the start of the icons when not conversations to keep them horizontally aligned with the notification icon -->
+ <dimen name="messaging_layout_icon_padding_start">4dp</dimen>
<!-- Padding between text and sender when singleline -->
<dimen name="messaging_group_singleline_sender_padding_end">4dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3208dff1d9f6..8d07ae254ee1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5151,6 +5151,8 @@
<!-- Action text to be displayed for the "answer" action of an incoming call [CHAR LIMIT=13] -->
<string name="call_notification_answer_action">Answer</string>
+ <!-- Action text to be displayed for the "answer" action of an incoming VIDEO call [CHAR LIMIT=13] -->
+ <string name="call_notification_answer_video_action">Video</string>
<!-- Action text to be displayed for the "decline" action of an incoming call [CHAR LIMIT=13] -->
<string name="call_notification_decline_action">Decline</string>
<!-- Action text to be displayed for the "hang up" action of an ongoing call [CHAR LIMIT=13] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3de2ac108021..d69c7f8f9587 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -275,6 +275,7 @@
<java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
<java-symbol type="bool" name="config_avoidGfxAccel" />
<java-symbol type="bool" name="config_bluetooth_address_validation" />
+ <java-symbol type="bool" name="config_flipToScreenOffEnabled" />
<java-symbol type="bool" name="config_bluetooth_sco_off_call" />
<java-symbol type="bool" name="config_bluetooth_le_peripheral_mode_supported" />
<java-symbol type="bool" name="config_bluetooth_hfp_inband_ringing_support" />
@@ -3015,6 +3016,7 @@
<java-symbol type="layout" name="app_anr_dialog" />
<java-symbol type="layout" name="notification_template_material_messaging" />
+ <java-symbol type="layout" name="notification_template_material_big_messaging" />
<java-symbol type="id" name="aerr_wait" />
@@ -3115,6 +3117,7 @@
<java-symbol type="layout" name="notification_template_material_call" />
<java-symbol type="layout" name="notification_template_material_big_call" />
<java-symbol type="string" name="call_notification_answer_action" />
+ <java-symbol type="string" name="call_notification_answer_video_action" />
<java-symbol type="string" name="call_notification_decline_action" />
<java-symbol type="string" name="call_notification_hang_up_action" />
<java-symbol type="string" name="call_notification_incoming_text" />
@@ -3124,6 +3127,7 @@
<java-symbol type="color" name="call_notification_answer_color"/>
<java-symbol type="dimen" name="call_notification_collapsible_indent"/>
<java-symbol type="drawable" name="ic_call_answer" />
+ <java-symbol type="drawable" name="ic_call_answer_video" />
<java-symbol type="drawable" name="ic_call_decline" />
<java-symbol type="id" name="verification_divider" />
<java-symbol type="id" name="verification_icon" />
@@ -3645,6 +3649,7 @@
<java-symbol type="id" name="bubble_button" />
<java-symbol type="id" name="snooze_button" />
<java-symbol type="dimen" name="text_size_body_2_material" />
+ <java-symbol type="dimen" name="notification_icon_circle_size" />
<java-symbol type="dimen" name="messaging_avatar_size" />
<java-symbol type="dimen" name="messaging_group_sending_progress_size" />
<java-symbol type="dimen" name="messaging_image_rounding" />
@@ -4061,7 +4066,7 @@
<java-symbol type="dimen" name="conversation_badge_side_margin_group_expanded_face_pile" />
<java-symbol type="dimen" name="conversation_content_start" />
<java-symbol type="dimen" name="expanded_group_conversation_message_padding" />
- <java-symbol type="dimen" name="messaging_layout_margin_end" />
+ <java-symbol type="dimen" name="messaging_layout_icon_padding_start" />
<java-symbol type="dimen" name="conversation_header_expanded_padding_end" />
<java-symbol type="dimen" name="conversation_icon_container_top_padding" />
<java-symbol type="dimen" name="conversation_icon_container_top_padding_small_avatar" />
@@ -4335,4 +4340,6 @@
<java-symbol type="drawable" name="ic_accessibility_24dp" />
<java-symbol type="string" name="view_and_control_notification_title" />
<java-symbol type="string" name="view_and_control_notification_content" />
+
+ <java-symbol type="layout" name="notification_expand_button"/>
</resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_amp_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_amp_24.xml
new file mode 100644
index 000000000000..1f5731821c94
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_amp_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="#d14d2c">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11.17,19.5h-0.83l0.82,-5.83 -4.18,0.01 5.85,-9.17h0.83l-0.84,5.84h4.17l-5.82,9.15z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_calculate_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_calculate_24.xml
new file mode 100644
index 000000000000..70aac32227c4
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_calculate_24.xml
@@ -0,0 +1,25 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="#269e5c">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.25,7.72h5v1.5h-5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,15.75h5v1.5h-5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,13.25h5v1.5h-5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,18l1.5,0l0,-2l2,0l0,-1.5l-2,0l0,-2l-1.5,0l0,2l-2,0l0,1.5l2,0z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.09,10.95l1.41,-1.41l1.41,1.41l1.06,-1.06l-1.41,-1.42l1.41,-1.41l-1.06,-1.06l-1.41,1.41l-1.41,-1.41l-1.06,1.06l1.41,1.41l-1.41,1.42z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_custom_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_custom_24.xml
new file mode 100644
index 000000000000..39f9689d2ec4
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_custom_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="#d14d2c">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,9L22,7h-2L20,5c0,-1.1 -0.9,-2 -2,-2L4,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-2h2v-2h-2v-2h2v-2h-2L20,9h2zM18,19L4,19L4,5h14v14zM6,13h5v4L6,17v-4zM12,7h4v3h-4L12,7zM6,7h5v5L6,12L6,7zM12,11h4v6h-4v-6z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_timer_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_timer_24.xml
new file mode 100644
index 000000000000..9cae545e165b
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_timer_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,3L9,3L9,1h6v2zM11,14h2L13,8h-2v6zM21,13.01c0,4.97 -4.02,9 -9,9s-9,-4.03 -9,-9 4.03,-9 9,-9c2.12,0 4.07,0.74 5.62,1.98l1.42,-1.42c0.51,0.42 0.98,0.9 1.41,1.41L19.03,7.4C20.26,8.93 21,10.89 21,13.01zM19,13.01c0,-3.87 -3.13,-7 -7,-7s-7,3.13 -7,7 3.13,7 7,7 7,-3.13 7,-7z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
index 1ced825adf31..98fc581f3420 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
@@ -25,6 +25,13 @@
android:paddingTop="8dp"
android:paddingBottom="8dp">
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="8dp"/>
+
<TextView
android:id="@+id/title"
android:layout_width="0dp"
@@ -34,16 +41,18 @@
<TextView
android:id="@+id/amount"
- android:layout_width="0dp"
- android:layout_weight="0.7"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
android:gravity="right"
+ android:maxLines="1"
android:textAppearance="@style/TextAppearanceBody"/>
<TextView
android:id="@+id/percent"
- android:layout_width="64dp"
+ android:layout_width="76dp"
android:layout_height="wrap_content"
android:gravity="right"
+ android:maxLines="1"
android:textAppearance="@style/TextAppearanceBody"/>
</LinearLayout>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
index e58a08fd362c..24d193c49219 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
@@ -43,10 +43,40 @@
android:paddingEnd="10dp">
<include layout="@layout/battery_consumer_info_layout"/>
-
</LinearLayout>
+
</androidx.cardview.widget.CardView>
+
+ <LinearLayout
+ android:id="@+id/headings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dp"
+ android:paddingBottom="4dp">
+ <FrameLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+ <TextView
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingEnd="10dp"
+ android:text="Total"/>
+ <TextView
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingEnd="30dp"
+ android:text="Apps"/>
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray"/>
+
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/battery_consumer_data_view"
android:layout_width="match_parent"
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml
new file mode 100644
index 000000000000..2dbe48b6edc0
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <color name="battery_consumer_bg_power_profile">#ffffff</color>
+ <color name="battery_consumer_bg_measured_energy">#fff5eb</color>
+</resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index 78569bdb4adc..f7d7098b1726 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -18,32 +18,21 @@ package com.android.frameworks.core.batterystatsviewer;
import android.content.Context;
import android.os.BatteryConsumer;
-import android.os.BatteryStats;
import android.os.BatteryUsageStats;
-import android.os.Process;
import android.os.SystemBatteryConsumer;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
-
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
+import android.util.DebugUtils;
import java.util.ArrayList;
import java.util.List;
public class BatteryConsumerData {
- private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
- private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media";
- private static final String PACKAGE_SYSTEMUI = "com.android.systemui";
- private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
- PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
-
- // Unit conversion:
- // mAh = uC * (1/1000)(milli/micro) * (1/3600)(hours/second)
- private static final double UC_2_MAH = (1.0 / 1000) * (1.0 / 3600);
enum EntryType {
- POWER,
+ POWER_MODELED,
+ POWER_MEASURED,
+ POWER_CUSTOM,
DURATION,
}
@@ -52,268 +41,155 @@ public class BatteryConsumerData {
public EntryType entryType;
public double value;
public double total;
+ public boolean isSystemBatteryConsumer;
}
private final BatteryConsumerInfoHelper.BatteryConsumerInfo mBatteryConsumerInfo;
private final List<Entry> mEntries = new ArrayList<>();
- public BatteryConsumerData(Context context, BatteryStatsHelper batteryStatsHelper,
+ public BatteryConsumerData(Context context,
List<BatteryUsageStats> batteryUsageStatsList, String batteryConsumerId) {
BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0);
- BatteryUsageStats powerProfileModeledUsageStats = batteryUsageStatsList.get(1);
- List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
- BatteryStats batteryStats = batteryStatsHelper.getStats();
-
- double totalPowerMah = 0;
- double totalSmearedPowerMah = 0;
- double totalPowerExcludeSystemMah = 0;
- double totalScreenPower = 0;
- double totalProportionalSmearMah = 0;
- double totalCpuPowerMah = 0;
- double totalSystemServiceCpuPowerMah = 0;
- double totalUsagePowerMah = 0;
- double totalWakeLockPowerMah = 0;
- double totalMobileRadioPowerMah = 0;
- double totalWifiPowerMah = 0;
- double totalBluetoothPowerMah = 0;
- double totalGpsPowerMah = 0;
- double totalCameraPowerMah = 0;
- double totalFlashlightPowerMah = 0;
- double totalSensorPowerMah = 0;
- double totalAudioPowerMah = 0;
- double totalVideoPowerMah = 0;
+ BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1);
- long totalCpuTimeMs = 0;
- long totalCpuFgTimeMs = 0;
- long totalWakeLockTimeMs = 0;
- long totalWifiRunningTimeMs = 0;
- long totalBluetoothRunningTimeMs = 0;
- long totalGpsTimeMs = 0;
- long totalCameraTimeMs = 0;
- long totalFlashlightTimeMs = 0;
- long totalAudioTimeMs = 0;
- long totalVideoTimeMs = 0;
+ BatteryConsumer requestedBatteryConsumer = getRequestedBatteryConsumer(batteryUsageStats,
+ batteryConsumerId);
+ BatteryConsumer requestedModeledBatteryConsumer = getRequestedBatteryConsumer(
+ modeledBatteryUsageStats, batteryConsumerId);
- BatterySipper requestedBatterySipper = null;
- for (BatterySipper sipper : usageList) {
- if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
- totalScreenPower = sipper.sumPower();
- }
-
- if (batteryConsumerId(sipper).equals(batteryConsumerId)) {
- requestedBatterySipper = sipper;
- }
-
- totalPowerMah += sipper.sumPower();
- totalSmearedPowerMah += sipper.totalSmearedPowerMah;
- totalProportionalSmearMah += sipper.proportionalSmearMah;
+ if (requestedBatteryConsumer == null || requestedModeledBatteryConsumer == null) {
+ mBatteryConsumerInfo = null;
+ return;
+ }
- if (!isSystemSipper(sipper)) {
- totalPowerExcludeSystemMah += sipper.totalSmearedPowerMah;
+ mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
+ context.getPackageManager(), requestedBatteryConsumer);
+
+ double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];
+ double[] totalModeledPowerByComponentMah =
+ new double[BatteryConsumer.POWER_COMPONENT_COUNT];
+ long[] totalDurationByComponentMs = new long[BatteryConsumer.TIME_COMPONENT_COUNT];
+ final int customComponentCount =
+ requestedBatteryConsumer.getCustomPowerComponentCount();
+ double[] totalCustomPowerByComponentMah = new double[customComponentCount];
+
+ computeTotalPower(batteryUsageStats, totalPowerByComponentMah);
+ computeTotalPower(modeledBatteryUsageStats, totalModeledPowerByComponentMah);
+ computeTotalPowerForCustomComponent(batteryUsageStats, totalCustomPowerByComponentMah);
+ computeTotalDuration(batteryUsageStats, totalDurationByComponentMs);
+
+ for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
+ final String metricTitle = getPowerMetricTitle(component);
+ final int powerModel = requestedBatteryConsumer.getPowerModel(component);
+ if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+ addEntry(metricTitle, EntryType.POWER_MODELED,
+ requestedBatteryConsumer.getConsumedPower(component),
+ totalPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
+ } else {
+ addEntry(metricTitle + " (measured)", EntryType.POWER_MEASURED,
+ requestedBatteryConsumer.getConsumedPower(component),
+ totalPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
+ addEntry(metricTitle + " (modeled)", EntryType.POWER_MODELED,
+ requestedModeledBatteryConsumer.getConsumedPower(component),
+ totalModeledPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
}
+ }
- totalCpuPowerMah += sipper.cpuPowerMah;
- totalSystemServiceCpuPowerMah += sipper.systemServiceCpuPowerMah;
- totalUsagePowerMah += sipper.usagePowerMah;
- totalWakeLockPowerMah += sipper.wakeLockPowerMah;
- totalMobileRadioPowerMah += sipper.mobileRadioPowerMah;
- totalWifiPowerMah += sipper.wifiPowerMah;
- totalBluetoothPowerMah += sipper.bluetoothPowerMah;
- totalGpsPowerMah += sipper.gpsPowerMah;
- totalCameraPowerMah += sipper.cameraPowerMah;
- totalFlashlightPowerMah += sipper.flashlightPowerMah;
- totalSensorPowerMah += sipper.sensorPowerMah;
- totalAudioPowerMah += sipper.audioPowerMah;
- totalVideoPowerMah += sipper.videoPowerMah;
-
- totalCpuTimeMs += sipper.cpuTimeMs;
- totalCpuFgTimeMs += sipper.cpuFgTimeMs;
- totalWakeLockTimeMs += sipper.wakeLockTimeMs;
- totalWifiRunningTimeMs += sipper.wifiRunningTimeMs;
- totalBluetoothRunningTimeMs += sipper.bluetoothRunningTimeMs;
- totalGpsTimeMs += sipper.gpsTimeMs;
- totalCameraTimeMs += sipper.cameraTimeMs;
- totalFlashlightTimeMs += sipper.flashlightTimeMs;
- totalAudioTimeMs += sipper.audioTimeMs;
- totalVideoTimeMs += sipper.videoTimeMs;
+ for (int component = 0; component < customComponentCount; component++) {
+ final String name = requestedBatteryConsumer.getCustomPowerComponentName(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
+ addEntry(name + " (custom)", EntryType.POWER_CUSTOM,
+ requestedBatteryConsumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component),
+ totalCustomPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
}
- BatteryConsumer requestedBatteryConsumer = null;
+ for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
+ final String metricTitle = getTimeMetricTitle(component);
+ addEntry(metricTitle, EntryType.DURATION,
+ requestedBatteryConsumer.getUsageDurationMillis(component),
+ totalDurationByComponentMs[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
+ }
+ }
+ private BatteryConsumer getRequestedBatteryConsumer(BatteryUsageStats batteryUsageStats,
+ String batteryConsumerId) {
for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
- requestedBatteryConsumer = consumer;
+ return consumer;
}
}
-
- double totalModeledCpuPowerMah = 0;
- BatteryConsumer requestedBatteryConsumerPowerProfileModeled = null;
- for (BatteryConsumer consumer : powerProfileModeledUsageStats.getUidBatteryConsumers()) {
+ for (BatteryConsumer consumer : batteryUsageStats.getSystemBatteryConsumers()) {
if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
- requestedBatteryConsumerPowerProfileModeled = consumer;
+ return consumer;
}
-
- totalModeledCpuPowerMah += consumer.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_CPU);
}
+ return null;
+ }
- if (requestedBatterySipper == null) {
- mBatteryConsumerInfo = null;
- return;
- }
+ static String getPowerMetricTitle(int componentId) {
+ final String componentName = DebugUtils.constantToString(BatteryConsumer.class,
+ "POWER_COMPONENT_", componentId);
+ return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ')
+ + " power";
+ }
+
+ static String getTimeMetricTitle(int componentId) {
+ final String componentName = DebugUtils.constantToString(BatteryConsumer.class,
+ "TIME_COMPONENT_", componentId);
+ return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ')
+ + " time";
+ }
- if (requestedBatteryConsumer == null) {
- for (BatteryConsumer consumer : batteryUsageStats.getSystemBatteryConsumers()) {
- if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
- requestedBatteryConsumer = consumer;
- break;
- }
+ private void computeTotalPower(BatteryUsageStats batteryUsageStats,
+ double[] powerByComponentMah) {
+ for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT;
+ component++) {
+ powerByComponentMah[component] += consumer.getConsumedPower(component);
}
}
+ }
- mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
- context.getPackageManager(), requestedBatterySipper);
- long totalScreenMeasuredChargeUC =
- batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
- long uidScreenMeasuredChargeUC =
- requestedBatterySipper.uidObj.getScreenOnMeasuredBatteryConsumptionUC();
-
- addEntry("Total power", EntryType.POWER,
- requestedBatterySipper.totalSmearedPowerMah, totalSmearedPowerMah);
- maybeAddMeasuredEnergyEntry(requestedBatterySipper.drainType, batteryStats);
-
- addEntry("... excluding system", EntryType.POWER,
- requestedBatterySipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
- addEntry("Screen, smeared", EntryType.POWER,
- requestedBatterySipper.screenPowerMah, totalScreenPower);
- if (uidScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE
- && totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
- final double measuredCharge = UC_2_MAH * uidScreenMeasuredChargeUC;
- final double totalMeasuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC;
- addEntry("Screen, measured", EntryType.POWER,
- measuredCharge, totalMeasuredCharge);
- }
- addEntry("Other, smeared", EntryType.POWER,
- requestedBatterySipper.proportionalSmearMah, totalProportionalSmearMah);
- addEntry("Excluding smeared", EntryType.POWER,
- requestedBatterySipper.totalPowerMah, totalPowerMah);
- if (requestedBatteryConsumer != null) {
- addEntry("CPU", EntryType.POWER,
- requestedBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU),
- totalCpuPowerMah);
- if (requestedBatteryConsumerPowerProfileModeled != null) {
- addEntry("CPU (modeled)", EntryType.POWER,
- requestedBatteryConsumerPowerProfileModeled.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_CPU),
- totalModeledCpuPowerMah);
+ private void computeTotalDuration(BatteryUsageStats batteryUsageStats,
+ long[] durationByComponentMs) {
+ for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT;
+ component++) {
+ durationByComponentMs[component] += consumer.getUsageDurationMillis(component);
}
- } else {
- addEntry("CPU (sipper)", EntryType.POWER,
- requestedBatterySipper.cpuPowerMah, totalCpuPowerMah);
}
- addEntry("System services", EntryType.POWER,
- requestedBatterySipper.systemServiceCpuPowerMah, totalSystemServiceCpuPowerMah);
- if (requestedBatteryConsumer != null) {
- addEntry("Usage", EntryType.POWER,
- requestedBatteryConsumer.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_USAGE), totalUsagePowerMah);
- } else {
- addEntry("Usage (sipper)", EntryType.POWER,
- requestedBatterySipper.usagePowerMah, totalUsagePowerMah);
- }
- addEntry("Wake lock", EntryType.POWER,
- requestedBatterySipper.wakeLockPowerMah, totalWakeLockPowerMah);
- addEntry("Mobile radio", EntryType.POWER,
- requestedBatterySipper.mobileRadioPowerMah, totalMobileRadioPowerMah);
- addEntry("WiFi", EntryType.POWER,
- requestedBatterySipper.wifiPowerMah, totalWifiPowerMah);
- addEntry("Bluetooth", EntryType.POWER,
- requestedBatterySipper.bluetoothPowerMah, totalBluetoothPowerMah);
- addEntry("GPS", EntryType.POWER,
- requestedBatterySipper.gpsPowerMah, totalGpsPowerMah);
- addEntry("Camera", EntryType.POWER,
- requestedBatterySipper.cameraPowerMah, totalCameraPowerMah);
- addEntry("Flashlight", EntryType.POWER,
- requestedBatterySipper.flashlightPowerMah, totalFlashlightPowerMah);
- addEntry("Sensors", EntryType.POWER,
- requestedBatterySipper.sensorPowerMah, totalSensorPowerMah);
- addEntry("Audio", EntryType.POWER,
- requestedBatterySipper.audioPowerMah, totalAudioPowerMah);
- addEntry("Video", EntryType.POWER,
- requestedBatterySipper.videoPowerMah, totalVideoPowerMah);
-
- addEntry("CPU time", EntryType.DURATION,
- requestedBatterySipper.cpuTimeMs, totalCpuTimeMs);
- addEntry("CPU foreground time", EntryType.DURATION,
- requestedBatterySipper.cpuFgTimeMs, totalCpuFgTimeMs);
- addEntry("Wake lock time", EntryType.DURATION,
- requestedBatterySipper.wakeLockTimeMs, totalWakeLockTimeMs);
- addEntry("WiFi running time", EntryType.DURATION,
- requestedBatterySipper.wifiRunningTimeMs, totalWifiRunningTimeMs);
- addEntry("Bluetooth time", EntryType.DURATION,
- requestedBatterySipper.bluetoothRunningTimeMs, totalBluetoothRunningTimeMs);
- addEntry("GPS time", EntryType.DURATION,
- requestedBatterySipper.gpsTimeMs, totalGpsTimeMs);
- addEntry("Camera time", EntryType.DURATION,
- requestedBatterySipper.cameraTimeMs, totalCameraTimeMs);
- addEntry("Flashlight time", EntryType.DURATION,
- requestedBatterySipper.flashlightTimeMs, totalFlashlightTimeMs);
- addEntry("Audio time", EntryType.DURATION,
- requestedBatterySipper.audioTimeMs, totalAudioTimeMs);
- addEntry("Video time", EntryType.DURATION,
- requestedBatterySipper.videoTimeMs, totalVideoTimeMs);
}
- private boolean isSystemSipper(BatterySipper sipper) {
- final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
- if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
- return true;
- } else if (sipper.mPackages != null) {
- for (final String packageName : sipper.mPackages) {
- for (final String systemPackage : PACKAGES_SYSTEM) {
- if (systemPackage.equals(packageName)) {
- return true;
- }
- }
+ private void computeTotalPowerForCustomComponent(
+ BatteryUsageStats batteryUsageStats, double[] powerByComponentMah) {
+ for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ final int customComponentCount = consumer.getCustomPowerComponentCount();
+ for (int component = 0;
+ component < Math.min(customComponentCount, powerByComponentMah.length);
+ component++) {
+ powerByComponentMah[component] += consumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
}
}
-
- return false;
}
- private void addEntry(String title, EntryType entryType, double amount, double totalAmount) {
+ private void addEntry(String title, EntryType entryType, double amount, double totalAmount,
+ boolean isSystemBatteryConsumer) {
Entry entry = new Entry();
entry.title = title;
entry.entryType = entryType;
entry.value = amount;
entry.total = totalAmount;
+ entry.isSystemBatteryConsumer = isSystemBatteryConsumer;
mEntries.add(entry);
}
- private void maybeAddMeasuredEnergyEntry(BatterySipper.DrainType drainType,
- BatteryStats batteryStats) {
- switch (drainType) {
- case AMBIENT_DISPLAY:
- final long totalDozeMeasuredChargeUC =
- batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
- if (totalDozeMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
- final double measuredCharge = UC_2_MAH * totalDozeMeasuredChargeUC;
- addEntry("Measured ambient display power", EntryType.POWER, measuredCharge,
- measuredCharge);
- }
- break;
- case SCREEN:
- final long totalScreenMeasuredChargeUC =
- batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
- if (totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
- final double measuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC;
- addEntry("Measured screen power", EntryType.POWER, measuredCharge,
- measuredCharge);
- }
- break;
- }
- }
-
public BatteryConsumerInfoHelper.BatteryConsumerInfo getBatteryConsumerInfo() {
return mBatteryConsumerInfo;
}
@@ -322,13 +198,9 @@ public class BatteryConsumerData {
return mEntries;
}
- public static String batteryConsumerId(BatterySipper sipper) {
- return sipper.drainType + "|" + sipper.userId + "|" + sipper.getUid();
- }
-
public static String batteryConsumerId(BatteryConsumer consumer) {
if (consumer instanceof UidBatteryConsumer) {
- return BatterySipper.DrainType.APP + "|"
+ return "APP|"
+ UserHandle.getUserId(((UidBatteryConsumer) consumer).getUid()) + "|"
+ ((UidBatteryConsumer) consumer).getUid();
} else if (consumer instanceof SystemBatteryConsumer) {
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
index 8ee6c604cb3e..6288e0b886d1 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
@@ -18,14 +18,14 @@ package com.android.frameworks.core.batterystatsviewer;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.os.BatteryConsumer;
import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.util.DebugUtils;
import androidx.annotation.NonNull;
-import com.android.internal.os.BatterySipper;
-
-import java.util.Locale;
-
class BatteryConsumerInfoHelper {
private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
@@ -37,111 +37,79 @@ class BatteryConsumerInfoHelper {
public ApplicationInfo iconInfo;
public CharSequence packages;
public CharSequence details;
+ public boolean isSystemBatteryConsumer;
}
@NonNull
public static BatteryConsumerInfo makeBatteryConsumerInfo(PackageManager packageManager,
- @NonNull BatterySipper sipper) {
+ @NonNull BatteryConsumer batteryConsumer) {
BatteryConsumerInfo info = new BatteryConsumerInfo();
- info.id = BatteryConsumerData.batteryConsumerId(sipper);
- sipper.sumPower();
- info.powerMah = sipper.totalSmearedPowerMah;
- switch (sipper.drainType) {
- case APP: {
- int uid = sipper.getUid();
- info.details = String.format("UID: %d", uid);
- String packageWithHighestDrain = sipper.packageWithHighestDrain;
- if (uid == Process.ROOT_UID) {
- info.label = "<root>";
- } else {
- String[] packages = packageManager.getPackagesForUid(uid);
- String primaryPackageName = null;
- if (uid == Process.SYSTEM_UID) {
- primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
- } else if (packages != null) {
- for (String name : packages) {
- primaryPackageName = name;
- if (name.equals(packageWithHighestDrain)) {
- break;
- }
+ info.id = BatteryConsumerData.batteryConsumerId(batteryConsumer);
+ info.powerMah = batteryConsumer.getConsumedPower();
+
+ if (batteryConsumer instanceof UidBatteryConsumer) {
+ final UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
+ int uid = uidBatteryConsumer.getUid();
+ info.details = String.format("UID: %d", uid);
+ String packageWithHighestDrain = uidBatteryConsumer.getPackageWithHighestDrain();
+ if (uid == Process.ROOT_UID) {
+ info.label = "<root>";
+ } else {
+ String[] packages = packageManager.getPackagesForUid(uid);
+ String primaryPackageName = null;
+ if (uid == Process.SYSTEM_UID) {
+ primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
+ } else if (packages != null) {
+ for (String name : packages) {
+ primaryPackageName = name;
+ if (name.equals(packageWithHighestDrain)) {
+ break;
}
}
+ }
- if (primaryPackageName != null) {
- try {
- ApplicationInfo applicationInfo =
- packageManager.getApplicationInfo(primaryPackageName, 0);
- info.label = applicationInfo.loadLabel(packageManager);
- info.iconInfo = applicationInfo;
- } catch (PackageManager.NameNotFoundException e) {
- info.label = primaryPackageName;
- }
- } else if (packageWithHighestDrain != null) {
- info.label = packageWithHighestDrain;
+ if (primaryPackageName != null) {
+ try {
+ ApplicationInfo applicationInfo =
+ packageManager.getApplicationInfo(primaryPackageName, 0);
+ info.label = applicationInfo.loadLabel(packageManager);
+ info.iconInfo = applicationInfo;
+ } catch (PackageManager.NameNotFoundException e) {
+ info.label = primaryPackageName;
}
+ } else if (packageWithHighestDrain != null) {
+ info.label = packageWithHighestDrain;
+ }
- if (packages != null && packages.length > 0) {
- StringBuilder sb = new StringBuilder();
- if (primaryPackageName != null) {
- sb.append(primaryPackageName);
+ if (packages != null && packages.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ if (primaryPackageName != null) {
+ sb.append(primaryPackageName);
+ }
+ for (String packageName : packages) {
+ if (packageName.equals(primaryPackageName)) {
+ continue;
}
- for (String packageName : packages) {
- if (packageName.equals(primaryPackageName)) {
- continue;
- }
- if (sb.length() != 0) {
- sb.append(", ");
- }
- sb.append(packageName);
+ if (sb.length() != 0) {
+ sb.append(", ");
}
-
- info.packages = sb;
+ sb.append(packageName);
}
+
+ info.packages = sb;
}
- break;
}
- case USER:
- info.label = "User";
- info.details = String.format(Locale.getDefault(), "User ID: %d", sipper.userId);
- break;
- case AMBIENT_DISPLAY:
- info.label = "Ambient display";
- break;
- case BLUETOOTH:
- info.label = "Bluetooth";
- break;
- case CAMERA:
- info.label = "Camera";
- break;
- case CELL:
- info.label = "Cell";
- break;
- case FLASHLIGHT:
- info.label = "Flashlight";
- break;
- case IDLE:
- info.label = "Idle";
- break;
- case MEMORY:
- info.label = "Memory";
- break;
- case OVERCOUNTED:
- info.label = "Overcounted";
- break;
- case PHONE:
- info.label = "Phone";
- break;
- case SCREEN:
- info.label = "Screen";
- break;
- case UNACCOUNTED:
- info.label = "Unaccounted";
- break;
- case WIFI:
- info.label = "WiFi";
- break;
+ } else if (batteryConsumer instanceof SystemBatteryConsumer) {
+ final SystemBatteryConsumer systemBatteryConsumer =
+ (SystemBatteryConsumer) batteryConsumer;
+ final int drainType = systemBatteryConsumer.getDrainType();
+ String name = DebugUtils.constantToString(SystemBatteryConsumer.class, "DRAIN_TYPE_",
+ drainType);
+ info.label = name.charAt(0) + name.substring(1).toLowerCase().replace('_', ' ');
+ info.isSystemBatteryConsumer = true;
}
+
// Default the app icon to System Server. This includes root, dex2oat and other UIDs.
if (info.iconInfo == null) {
try {
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java
index bb11fd598511..49220877d31e 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java
@@ -18,10 +18,11 @@ package com.android.frameworks.core.batterystatsviewer;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.BatteryStats;
+import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,8 +38,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.frameworks.core.batterystatsviewer.BatteryConsumerInfoHelper.BatteryConsumerInfo;
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.ArrayList;
@@ -99,44 +98,39 @@ public class BatteryConsumerPickerFragment extends Fragment {
private static class BatteryConsumerListLoader extends
AsyncLoaderCompat<List<BatteryConsumerInfo>> {
- private final BatteryStatsHelper mStatsHelper;
private final int mPickerType;
- private final UserManager mUserManager;
+ private final BatteryStatsManager mBatteryStatsManager;
private final PackageManager mPackageManager;
BatteryConsumerListLoader(Context context, int pickerType) {
super(context);
- mUserManager = context.getSystemService(UserManager.class);
- mStatsHelper = new BatteryStatsHelper(context, false /* collectBatteryBroadcast */);
+ mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class);
mPickerType = pickerType;
- mStatsHelper.create((Bundle) null);
- mStatsHelper.clearStats();
mPackageManager = context.getPackageManager();
}
@Override
public List<BatteryConsumerInfo> loadInBackground() {
- List<BatteryConsumerInfo> batteryConsumerList = new ArrayList<>();
+ final BatteryUsageStats batteryUsageStats = mBatteryStatsManager.getBatteryUsageStats();
- mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
- final List<BatterySipper> usageList = mStatsHelper.getUsageList();
- for (BatterySipper sipper : usageList) {
- switch (mPickerType) {
- case PICKER_TYPE_APP:
- if (sipper.drainType != BatterySipper.DrainType.APP) {
- continue;
- }
- break;
- case PICKER_TYPE_DRAIN:
- default:
- if (sipper.drainType == BatterySipper.DrainType.APP) {
- continue;
- }
- }
-
- batteryConsumerList.add(
- BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager, sipper));
+ List<BatteryConsumerInfo> batteryConsumerList = new ArrayList<>();
+ switch (mPickerType) {
+ case PICKER_TYPE_APP:
+ for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ batteryConsumerList.add(
+ BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager,
+ consumer));
+ }
+ break;
+ case PICKER_TYPE_DRAIN:
+ default:
+ for (SystemBatteryConsumer consumer :
+ batteryUsageStats.getSystemBatteryConsumers()) {
+ batteryConsumerList.add(
+ BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager,
+ consumer));
+ }
+ break;
}
batteryConsumerList.sort(
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
index 4ead8eef5684..74d3fb336f40 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
@@ -18,13 +18,10 @@ package com.android.frameworks.core.batterystatsviewer;
import android.content.Context;
import android.content.SharedPreferences;
-import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -41,7 +38,6 @@ import androidx.loader.content.Loader;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.Collections;
@@ -50,24 +46,24 @@ import java.util.Locale;
public class BatteryStatsViewerActivity extends ComponentActivity {
private static final int BATTERY_STATS_REFRESH_RATE_MILLIS = 60 * 1000;
- public static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId";
- public static final int LOADER_BATTERY_STATS_HELPER = 0;
- public static final int LOADER_BATTERY_USAGE_STATS = 1;
+ private static final int MILLIS_IN_MINUTE = 60000;
+ private static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId";
+ private static final int LOADER_BATTERY_USAGE_STATS = 1;
private BatteryStatsDataAdapter mBatteryStatsDataAdapter;
- private Runnable mBatteryStatsRefresh = this::periodicBatteryStatsRefresh;
+ private final Runnable mBatteryStatsRefresh = this::periodicBatteryStatsRefresh;
private SharedPreferences mSharedPref;
private String mBatteryConsumerId;
private TextView mTitleView;
private TextView mDetailsView;
private ImageView mIconView;
private TextView mPackagesView;
+ private View mHeadingsView;
private RecyclerView mBatteryConsumerDataView;
private View mLoadingView;
private View mEmptyView;
- private ActivityResultLauncher<Void> mStartAppPicker = registerForActivityResult(
+ private final ActivityResultLauncher<Void> mStartAppPicker = registerForActivityResult(
BatteryConsumerPickerActivity.CONTRACT, this::onApplicationSelected);
- private BatteryStatsHelper mBatteryStatsHelper;
private List<BatteryUsageStats> mBatteryUsageStats;
@Override
@@ -85,6 +81,7 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
mDetailsView = findViewById(R.id.details);
mIconView = findViewById(android.R.id.icon);
mPackagesView = findViewById(R.id.packages);
+ mHeadingsView = findViewById(R.id.headings);
mBatteryConsumerDataView = findViewById(R.id.battery_consumer_data_view);
mBatteryConsumerDataView.setLayoutManager(new LinearLayoutManager(this));
@@ -139,55 +136,10 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
private void loadBatteryStats() {
LoaderManager loaderManager = LoaderManager.getInstance(this);
- loaderManager.restartLoader(LOADER_BATTERY_STATS_HELPER, null,
- new BatteryStatsHelperLoaderCallbacks());
loaderManager.restartLoader(LOADER_BATTERY_USAGE_STATS, null,
new BatteryUsageStatsLoaderCallbacks());
}
- private static class BatteryStatsHelperLoader extends AsyncLoaderCompat<BatteryStatsHelper> {
- private final BatteryStatsHelper mBatteryStatsHelper;
- private final UserManager mUserManager;
-
- BatteryStatsHelperLoader(Context context) {
- super(context);
- mUserManager = context.getSystemService(UserManager.class);
- mBatteryStatsHelper = new BatteryStatsHelper(context,
- false /* collectBatteryBroadcast */);
- mBatteryStatsHelper.create((Bundle) null);
- mBatteryStatsHelper.clearStats();
- }
-
- @Override
- public BatteryStatsHelper loadInBackground() {
- mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
- UserHandle.myUserId());
- return mBatteryStatsHelper;
- }
-
- @Override
- protected void onDiscardResult(BatteryStatsHelper result) {
- }
- }
-
- private class BatteryStatsHelperLoaderCallbacks implements LoaderCallbacks<BatteryStatsHelper> {
- @NonNull
- @Override
- public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
- return new BatteryStatsHelperLoader(BatteryStatsViewerActivity.this);
- }
-
- @Override
- public void onLoadFinished(@NonNull Loader<BatteryStatsHelper> loader,
- BatteryStatsHelper batteryStatsHelper) {
- onBatteryStatsHelperLoaded(batteryStatsHelper);
- }
-
- @Override
- public void onLoaderReset(@NonNull Loader<BatteryStatsHelper> loader) {
- }
- }
-
private static class BatteryUsageStatsLoader extends
AsyncLoaderCompat<List<BatteryUsageStats>> {
private final BatteryStatsManager mBatteryStatsManager;
@@ -200,10 +152,13 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
@Override
public List<BatteryUsageStats> loadInBackground() {
final BatteryUsageStatsQuery queryDefault =
- new BatteryUsageStatsQuery.Builder().build();
+ new BatteryUsageStatsQuery.Builder()
+ .includePowerModels()
+ .build();
final BatteryUsageStatsQuery queryPowerProfileModeledOnly =
new BatteryUsageStatsQuery.Builder()
.powerProfileModeledOnly()
+ .includePowerModels()
.build();
return mBatteryStatsManager.getBatteryUsageStats(
List.of(queryDefault, queryPowerProfileModeledOnly));
@@ -233,22 +188,13 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
}
}
- public void onBatteryStatsHelperLoaded(BatteryStatsHelper batteryStatsHelper) {
- mBatteryStatsHelper = batteryStatsHelper;
- onBatteryStatsDataLoaded();
- }
-
private void onBatteryUsageStatsLoaded(List<BatteryUsageStats> batteryUsageStats) {
mBatteryUsageStats = batteryUsageStats;
onBatteryStatsDataLoaded();
}
public void onBatteryStatsDataLoaded() {
- if (mBatteryStatsHelper == null || mBatteryUsageStats == null) {
- return;
- }
-
- BatteryConsumerData batteryConsumerData = new BatteryConsumerData(this, mBatteryStatsHelper,
+ BatteryConsumerData batteryConsumerData = new BatteryConsumerData(this,
mBatteryUsageStats, mBatteryConsumerId);
BatteryConsumerInfoHelper.BatteryConsumerInfo
@@ -256,6 +202,7 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
if (batteryConsumerInfo == null) {
mTitleView.setText("Battery consumer not found");
mPackagesView.setVisibility(View.GONE);
+ mHeadingsView.setVisibility(View.GONE);
} else {
mTitleView.setText(batteryConsumerInfo.label);
if (batteryConsumerInfo.details != null) {
@@ -273,6 +220,12 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
} else {
mPackagesView.setVisibility(View.GONE);
}
+
+ if (batteryConsumerInfo.isSystemBatteryConsumer) {
+ mHeadingsView.setVisibility(View.VISIBLE);
+ } else {
+ mHeadingsView.setVisibility(View.GONE);
+ }
}
mBatteryStatsDataAdapter.setEntries(batteryConsumerData.getEntries());
@@ -290,6 +243,7 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
private static class BatteryStatsDataAdapter extends
RecyclerView.Adapter<BatteryStatsDataAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder {
+ public ImageView iconImageView;
public TextView titleTextView;
public TextView amountTextView;
public TextView percentTextView;
@@ -297,6 +251,7 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
ViewHolder(View itemView) {
super(itemView);
+ iconImageView = itemView.findViewById(R.id.icon);
titleTextView = itemView.findViewById(R.id.title);
amountTextView = itemView.findViewById(R.id.amount);
percentTextView = itemView.findViewById(R.id.percent);
@@ -328,21 +283,56 @@ public class BatteryStatsViewerActivity extends ComponentActivity {
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
BatteryConsumerData.Entry entry = mEntries.get(position);
switch (entry.entryType) {
- case POWER:
+ case POWER_MODELED:
viewHolder.titleTextView.setText(entry.title);
viewHolder.amountTextView.setText(
String.format(Locale.getDefault(), "%.1f mAh", entry.value));
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_calculate_24);
+ viewHolder.itemView.setBackgroundResource(
+ R.color.battery_consumer_bg_power_profile);
break;
- case DURATION:
+ case POWER_MEASURED:
viewHolder.titleTextView.setText(entry.title);
viewHolder.amountTextView.setText(
- String.format(Locale.getDefault(), "%,d ms", (long) entry.value));
+ String.format(Locale.getDefault(), "%.1f mAh", entry.value));
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_amp_24);
+ viewHolder.itemView.setBackgroundResource(
+ R.color.battery_consumer_bg_measured_energy);
+ break;
+ case POWER_CUSTOM:
+ viewHolder.titleTextView.setText(entry.title);
+ viewHolder.amountTextView.setText(
+ String.format(Locale.getDefault(), "%.1f mAh", entry.value));
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_custom_24);
+ viewHolder.itemView.setBackgroundResource(
+ R.color.battery_consumer_bg_measured_energy);
+ break;
+ case DURATION:
+ viewHolder.titleTextView.setText(entry.title);
+ final long durationMs = (long) entry.value;
+ CharSequence text;
+ if (durationMs < MILLIS_IN_MINUTE) {
+ text = String.format(Locale.getDefault(), "%,d ms", durationMs);
+ } else {
+ text = String.format(Locale.getDefault(), "%,d m %d s",
+ durationMs / MILLIS_IN_MINUTE,
+ (durationMs % MILLIS_IN_MINUTE) / 1000);
+ }
+
+ viewHolder.amountTextView.setText(text);
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_timer_24);
+ viewHolder.itemView.setBackground(null);
break;
}
- double proportion = entry.total != 0 ? entry.value * 100 / entry.total : 0;
- viewHolder.percentTextView.setText(String.format(Locale.getDefault(), "%.1f%%",
- proportion));
+ double proportion;
+ if (entry.isSystemBatteryConsumer) {
+ proportion = entry.value != 0 ? entry.total * 100 / entry.value : 0;
+ } else {
+ proportion = entry.total != 0 ? entry.value * 100 / entry.total : 0;
+ }
+ viewHolder.percentTextView.setText(
+ String.format(Locale.getDefault(), "%.1f%%", proportion));
}
}
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index e5da41c7c113..2e2e6bd07539 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -86,7 +86,6 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
@MediumTest
@Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
public class ActivityThreadTest {
private static final int TIMEOUT_SEC = 10;
@@ -352,8 +351,9 @@ public class ActivityThreadTest {
final Rect bounds = activity.getWindowManager().getCurrentWindowMetrics().getBounds();
assertEquals(activityConfigPortrait.windowConfiguration.getBounds(), bounds);
- // Ensure that Activity#onConfigurationChanged() is only called once.
- assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+ // Ensure that Activity#onConfigurationChanged() not be called because the changes in
+ // WindowConfiguration shouldn't be reported.
+ assertEquals(numOfConfig, activity.mNumOfConfigChanges);
}
@Test
@@ -379,7 +379,7 @@ public class ActivityThreadTest {
Configuration config = new Configuration();
config.seq = BASE_SEQ + 1;
- config.smallestScreenWidthDp = 100;
+ config.orientation = ORIENTATION_LANDSCAPE;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
// Wait until the main thread is performing the configuration change for the configuration
@@ -389,17 +389,17 @@ public class ActivityThreadTest {
config = new Configuration();
config.seq = BASE_SEQ + 2;
- config.smallestScreenWidthDp = 200;
+ config.orientation = ORIENTATION_PORTRAIT;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
config = new Configuration();
config.seq = BASE_SEQ + 3;
- config.smallestScreenWidthDp = 300;
+ config.orientation = ORIENTATION_LANDSCAPE;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
config = new Configuration();
config.seq = BASE_SEQ + 4;
- config.smallestScreenWidthDp = 400;
+ config.orientation = ORIENTATION_PORTRAIT;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
activity.mConfigLatch.countDown();
@@ -411,7 +411,7 @@ public class ActivityThreadTest {
// Only two more configuration changes: one with seq BASE_SEQ + 1; another with seq
// BASE_SEQ + 4. Configurations scheduled in between should be dropped.
assertEquals(numOfConfig + 2, activity.mNumOfConfigChanges);
- assertEquals(400, activity.mConfig.smallestScreenWidthDp);
+ assertEquals(ORIENTATION_PORTRAIT, activity.mConfig.orientation);
}
@Test
@@ -515,6 +515,7 @@ public class ActivityThreadTest {
}
@Test
+ @FlakyTest(bugId = 176134235)
public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/core/tests/coretests/src/android/window/WindowContextTest.java b/core/tests/coretests/src/android/window/WindowContextTest.java
index 614e7c1d6fa4..83280f18c889 100644
--- a/core/tests/coretests/src/android/window/WindowContextTest.java
+++ b/core/tests/coretests/src/android/window/WindowContextTest.java
@@ -17,6 +17,7 @@
package android.window;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -209,6 +210,38 @@ public class WindowContextTest {
mWms.removeWindowToken(existingToken, DEFAULT_DISPLAY);
}
+ @Test
+ public void testWindowContextAddViewWithSubWindowType_NotCrash() throws Throwable {
+ final WindowContext windowContext = createWindowContext(TYPE_INPUT_METHOD);
+ final WindowManager wm = windowContext.getSystemService(WindowManager.class);
+
+ // Create a WindowToken with system window type.
+ final IBinder existingToken = new Binder();
+ mWms.addWindowToken(existingToken, TYPE_INPUT_METHOD, windowContext.getDisplayId(),
+ null /* options */);
+
+ final WindowManager.LayoutParams params =
+ new WindowManager.LayoutParams(TYPE_INPUT_METHOD);
+ params.token = existingToken;
+ final View parentWindow = new View(windowContext);
+
+ final AttachStateListener listener = new AttachStateListener();
+ parentWindow.addOnAttachStateChangeListener(listener);
+
+ // Add the parent window
+ mInstrumentation.runOnMainSync(() -> wm.addView(parentWindow, params));
+
+ assertTrue(listener.mLatch.await(4, TimeUnit.SECONDS));
+
+ final WindowManager.LayoutParams subWindowAttrs =
+ new WindowManager.LayoutParams(TYPE_APPLICATION_ATTACHED_DIALOG);
+ subWindowAttrs.token = parentWindow.getWindowToken();
+ final View subWindow = new View(windowContext);
+
+ // Add a window with sub-window type.
+ mInstrumentation.runOnMainSync(() -> wm.addView(subWindow, subWindowAttrs));
+ }
+
private WindowContext createWindowContext() {
return createWindowContext(TYPE_APPLICATION_OVERLAY);
}
@@ -219,4 +252,16 @@ public class WindowContextTest {
.getDisplay(DEFAULT_DISPLAY);
return (WindowContext) instContext.createWindowContext(display, type, null /* options */);
}
+
+ private static class AttachStateListener implements View.OnAttachStateChangeListener {
+ final CountDownLatch mLatch = new CountDownLatch(1);
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {}
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
index cf47efddddd9..c63ec45ed5a9 100644
--- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
@@ -65,12 +65,12 @@ public class AmbientDisplayPowerCalculatorTest {
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(90 * MINUTE_IN_MS);
// 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(27.777778);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
}
@@ -91,11 +91,11 @@ public class AmbientDisplayPowerCalculatorTest {
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(90 * MINUTE_IN_MS);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(15.0);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 1e614c480bde..3a6f7b8a1618 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -109,11 +109,11 @@ public class BatteryUsageStatsRule implements TestRule {
}
/** Call only after setting the power profile information. */
- public BatteryUsageStatsRule initMeasuredEnergyStatsLocked(int numCustom) {
+ public BatteryUsageStatsRule initMeasuredEnergyStatsLocked() {
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
Arrays.fill(supportedStandardBuckets, true);
- mBatteryStats.initMeasuredEnergyStatsLocked(supportedStandardBuckets, numCustom);
+ mBatteryStats.initMeasuredEnergyStatsLocked(supportedStandardBuckets, new String[0]);
mBatteryStats.informThatAllExternalStatsAreFlushed();
return this;
}
@@ -167,15 +167,11 @@ public class BatteryUsageStatsRule implements TestRule {
}
BatteryUsageStats apply(BatteryUsageStatsQuery query, PowerCalculator... calculators) {
- final long[] customMeasuredEnergiesMicroJoules =
- mBatteryStats.getCustomConsumerMeasuredBatteryConsumptionUC();
- final int customMeasuredEnergiesCount = customMeasuredEnergiesMicroJoules != null
- ? customMeasuredEnergiesMicroJoules.length
- : 0;
+ final String[] customPowerComponentNames = mBatteryStats.getCustomPowerComponentNames();
final boolean includePowerModels = (query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
- customMeasuredEnergiesCount, 0, includePowerModels);
+ customPowerComponentNames, 0, includePowerModels);
SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
for (int i = 0; i < uidStats.size(); i++) {
builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 60df9688b5a4..b25359970c5a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -66,17 +66,18 @@ public class BatteryUsageStatsTest {
final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
- final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1)
- .setDischargePercentage(20)
- .setDischargedPowerRange(1000, 2000)
- .setStatsStartTimestamp(1000);
+ final BatteryUsageStats.Builder builder =
+ new BatteryUsageStats.Builder(new String[]{"FOO"}, 1)
+ .setDischargePercentage(20)
+ .setDischargedPowerRange(1000, 2000)
+ .setStatsStartTimestamp(1000);
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid)
.setPackageWithHighestDrain("foo")
.setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000)
.setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, 2000)
.setConsumedPower(
- BatteryConsumer.POWER_COMPONENT_USAGE, 300)
+ BatteryConsumer.POWER_COMPONENT_SCREEN, 300)
.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_CPU, 400)
.setConsumedPowerForCustomComponent(
@@ -122,7 +123,7 @@ public class BatteryUsageStatsTest {
assertThat(uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_BACKGROUND)).isEqualTo(2000);
assertThat(uidBatteryConsumer.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
+ BatteryConsumer.POWER_COMPONENT_SCREEN)).isEqualTo(300);
assertThat(uidBatteryConsumer.getConsumedPower(
BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(400);
assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent(
@@ -134,6 +135,9 @@ public class BatteryUsageStatsTest {
assertThat(uidBatteryConsumer.getUsageDurationForCustomComponentMillis(
BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(800);
assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(1200);
+ assertThat(uidBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
+ assertThat(uidBatteryConsumer.getCustomPowerComponentName(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
} else {
fail("Unexpected UID " + uidBatteryConsumer.getUid());
}
@@ -153,6 +157,11 @@ public class BatteryUsageStatsTest {
BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(10400);
assertThat(systemBatteryConsumer.getConsumedPower()).isEqualTo(20300);
assertThat(systemBatteryConsumer.getPowerConsumedByApps()).isEqualTo(20000);
+ assertThat(systemBatteryConsumer.getUsageDurationMillis())
+ .isEqualTo(10400); // max
+ assertThat(systemBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
+ assertThat(systemBatteryConsumer.getCustomPowerComponentName(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
} else {
fail("Unexpected drain type " + systemBatteryConsumer.getDrainType());
}
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 f65fb9583d6c..bf87683593e7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
@@ -16,6 +16,8 @@
package com.android.internal.os;
+import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -23,16 +25,21 @@ import static org.junit.Assert.assertEquals;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
+import android.util.proto.ProtoOutputStream;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.BinderInternal.CallSession;
import com.android.internal.os.BinderLatencyObserver.LatencyDims;
+import com.android.internal.os.BinderLatencyProto.ApiStats;
+import com.android.internal.os.BinderLatencyProto.Dims;
+import com.android.internal.os.BinderLatencyProto.RepeatedApiStats;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
@@ -49,11 +56,17 @@ public class BinderLatencyObserverTest {
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
+ blo.setElapsedTime(4);
blo.callEnded(callSession);
+ blo.setElapsedTime(6);
blo.callEnded(callSession);
callSession.transactionCode = 2;
+ blo.setElapsedTime(8);
blo.callEnded(callSession);
+ blo.setElapsedTime(10);
blo.callEnded(callSession);
ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms();
@@ -74,8 +87,10 @@ public class BinderLatencyObserverTest {
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
callSession.transactionCode = 2;
+ blo.setElapsedTime(4);
blo.callEnded(callSession);
ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms();
@@ -89,13 +104,13 @@ public class BinderLatencyObserverTest {
@Test
public void testTooCallLengthOverflow() {
TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
- blo.setElapsedTime(2L + (long) Integer.MAX_VALUE);
blo.setHistogramBucketsParams(5, 5, 1.125f);
Binder binder = new Binder();
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+ blo.setElapsedTime(2L + (long) Integer.MAX_VALUE);
blo.callEnded(callSession);
// The long call should be capped to maxint (to not overflow) and placed in the last bucket.
@@ -114,6 +129,7 @@ public class BinderLatencyObserverTest {
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
LatencyDims dims = new LatencyDims(binder.getClass(), 1);
@@ -122,14 +138,111 @@ public class BinderLatencyObserverTest {
assertThat(blo.getLatencyHistograms().get(dims))
.asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
// Try to add another sample.
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
// Make sure the buckets don't overflow.
assertThat(blo.getLatencyHistograms().get(dims))
.asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
}
+ @Test
+ public void testSingleAtomPush() {
+ TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
+
+ Binder binder = new Binder();
+ CallSession callSession = new CallSession();
+ callSession.binderClass = binder.getClass();
+ callSession.transactionCode = 1;
+ blo.setElapsedTime(7);
+ blo.callEnded(callSession);
+ blo.callEnded(callSession);
+ blo.setElapsedTime(8);
+ blo.callEnded(callSession);
+
+ // Trigger the statsd push.
+ blo.getStatsdPushRunnable().run();
+
+ ProtoOutputStream expectedProto = new ProtoOutputStream();
+ long apiStatsToken = expectedProto.start(RepeatedApiStats.API_STATS);
+ long dimsToken = expectedProto.start(ApiStats.DIMS);
+ expectedProto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto.write(Dims.SERVICE_METHOD_NAME, "1");
+ expectedProto.end(dimsToken);
+ expectedProto.write(ApiStats.FIRST_BUCKET_INDEX, 3);
+ expectedProto.write(ApiStats.BUCKETS, 2);
+ expectedProto.write(ApiStats.BUCKETS, 1);
+ expectedProto.end(apiStatsToken);
+
+ assertThat(blo.getWrittenAtoms())
+ .containsExactly(Arrays.toString(expectedProto.getBytes()));
+ }
+
+ @Test
+ public void testMultipleAtomPush() {
+ TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
+
+ BinderTransactionNameResolver resolver = new BinderTransactionNameResolver();
+
+
+ Binder binder = new Binder();
+ CallSession callSession = new CallSession();
+ callSession.binderClass = binder.getClass();
+ callSession.transactionCode = 1;
+ blo.setElapsedTime(1);
+ blo.callEnded(callSession);
+ callSession.transactionCode = 2;
+ blo.setElapsedTime(5);
+ blo.callEnded(callSession);
+ callSession.transactionCode = 3;
+ blo.callEnded(callSession);
+
+ // Trigger the statsd push.
+ blo.getStatsdPushRunnable().run();
+
+ ProtoOutputStream expectedProto1 = new ProtoOutputStream();
+ long apiStatsToken = expectedProto1.start(RepeatedApiStats.API_STATS);
+ long dimsToken = expectedProto1.start(ApiStats.DIMS);
+ expectedProto1.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto1.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto1.write(Dims.SERVICE_METHOD_NAME, "1");
+ expectedProto1.end(dimsToken);
+ expectedProto1.write(ApiStats.FIRST_BUCKET_INDEX, 0);
+ expectedProto1.write(ApiStats.BUCKETS, 1);
+ expectedProto1.end(apiStatsToken);
+
+ apiStatsToken = expectedProto1.start(RepeatedApiStats.API_STATS);
+ dimsToken = expectedProto1.start(ApiStats.DIMS);
+ expectedProto1.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto1.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto1.write(Dims.SERVICE_METHOD_NAME, "2");
+ expectedProto1.end(dimsToken);
+ expectedProto1.write(ApiStats.FIRST_BUCKET_INDEX, 1);
+ expectedProto1.write(ApiStats.BUCKETS, 1);
+ expectedProto1.end(apiStatsToken);
+
+ ProtoOutputStream expectedProto2 = new ProtoOutputStream();
+ apiStatsToken = expectedProto2.start(RepeatedApiStats.API_STATS);
+ dimsToken = expectedProto2.start(ApiStats.DIMS);
+ expectedProto2.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto2.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto2.write(Dims.SERVICE_METHOD_NAME, "3");
+ expectedProto2.end(dimsToken);
+ expectedProto2.write(ApiStats.FIRST_BUCKET_INDEX, 1);
+ expectedProto2.write(ApiStats.BUCKETS, 1);
+ expectedProto2.end(apiStatsToken);
+
+ // Each ApiStats is around ~60 bytes so only two should fit in an atom.
+ assertThat(blo.getWrittenAtoms())
+ .containsExactly(
+ Arrays.toString(expectedProto1.getBytes()),
+ Arrays.toString(expectedProto2.getBytes()))
+ .inOrder();
+ }
+
public static class TestBinderLatencyObserver extends BinderLatencyObserver {
private long mElapsedTime = 0;
+ private ArrayList<String> mWrittenAtoms;
TestBinderLatencyObserver() {
// Make random generator not random.
@@ -145,16 +258,30 @@ public class BinderLatencyObserverTest {
}
});
setSamplingInterval(1);
+ mWrittenAtoms = new ArrayList<>();
}
@Override
protected long getElapsedRealtimeMicro() {
- mElapsedTime += 2;
return mElapsedTime;
}
+ @Override
+ protected int getMaxAtomSizeBytes() {
+ return 1100;
+ }
+
+ @Override
+ protected void writeAtomToStatsd(ProtoOutputStream atom) {
+ mWrittenAtoms.add(Arrays.toString(atom.getBytes()));
+ }
+
public void setElapsedTime(long time) {
mElapsedTime = time;
}
+
+ public ArrayList<String> getWrittenAtoms() {
+ return mWrittenAtoms;
+ }
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 1a87c1084fe0..71cdb5fe17f0 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -44,7 +44,7 @@ public class BluetoothPowerCalculatorTest {
.setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE, 10.0)
.setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX, 50.0)
.setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0)
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
@Test
public void testTimerBasedModel() {
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index 31abbc20a090..63af21dcdd93 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -96,7 +96,7 @@ public class CpuPowerCalculatorTest {
.setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader)
.setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader)
.setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
- .initMeasuredEnergyStatsLocked(supportedPowerBuckets, 0);
+ .initMeasuredEnergyStatsLocked(supportedPowerBuckets, new String[0]);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
index 95c3b4ed8a40..aa066c36cd4b 100644
--- a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
@@ -42,7 +42,7 @@ public class GnssPowerCalculatorTest {
.setAveragePower(PowerProfile.POWER_GPS_ON, 360.0)
.setAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED,
new double[] {720.0, 1440.0, 1800.0})
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
@Test
public void testTimerBasedModel() {
diff --git a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
index 781e72560279..a9800b7e6b75 100644
--- a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
@@ -48,9 +48,9 @@ public class IdlePowerCalculatorTest {
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_IDLE);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE))
.isEqualTo(3000);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE))
.isWithin(PRECISION).of(0.7);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
index 8f21503a6d77..71dbcdbf7f46 100644
--- a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
@@ -55,9 +55,9 @@ public class MemoryPowerCalculatorTest {
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MEMORY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY))
.isEqualTo(3000);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY))
.isWithin(PRECISION).of(0.7);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index 3505e8c34027..5b84a1b320c7 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -57,7 +57,7 @@ public class MobileRadioPowerCalculatorTest {
.setAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX, 1440.0)
.setAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX,
new double[] {720.0, 1080.0, 1440.0, 1800.0, 2160.0})
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
@Test
public void testCounterBasedModel() {
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 26adbe9e7c59..7a7d9f541328 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -51,7 +51,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
Arrays.fill(supportedStandardBuckets, true);
- mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedStandardBuckets, 2);
+ final String[] customBucketNames = {"FOO", "BAR"};
+ mGlobalMeasuredEnergyStats =
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
// A no-op handler.
mHandler = new Handler(Looper.getMainLooper()) {
diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
index 9cd6ea8a6a3b..7d829e44d9ec 100644
--- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
@@ -84,13 +84,13 @@ public class ScreenPowerCalculatorTest {
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(80 * MINUTE_IN_MS);
// 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s) = 166.66666 mAh
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(166.66666);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
assertThat(consumer.getConsumedPower())
.isWithin(PRECISION).of(166.66666);
@@ -153,11 +153,11 @@ public class ScreenPowerCalculatorTest {
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(80 * MINUTE_IN_MS);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(92.0);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
assertThat(consumer.getConsumedPower())
.isWithin(PRECISION).of(92.0);
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index 2e501dbe355e..9349bce2c383 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -53,7 +53,7 @@ public class WifiPowerCalculatorTest {
.setAveragePower(PowerProfile.POWER_WIFI_SCAN, 480.0)
.setAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, 720.0)
.setAveragePower(PowerProfile.POWER_WIFI_ACTIVE, 1080.0)
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
/** Sets up a batterystats object with pre-populated network values. */
private BatteryStatsImpl setupTestNetworkNumbers() {
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
index ed6e27b199b9..f1edc871a56c 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -23,6 +23,8 @@ import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN
import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON;
import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_OTHER;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -49,13 +51,13 @@ public class MeasuredEnergyStatsTest {
@Test
public void testConstruction() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
if (supportedStandardBuckets[i]) {
@@ -66,21 +68,22 @@ public class MeasuredEnergyStatsTest {
assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(0L, stats.getAccumulatedCustomBucketCharge(i));
}
+ assertThat(stats.getCustomBucketNames()).asList().containsExactly("A", "B");
}
@Test
public void testCreateFromTemplate() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -99,7 +102,7 @@ public class MeasuredEnergyStatsTest {
newStats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(i));
}
}
@@ -107,13 +110,13 @@ public class MeasuredEnergyStatsTest {
@Test
public void testReadWriteParcel() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -130,25 +133,25 @@ public class MeasuredEnergyStatsTest {
assertEquals(stats.getAccumulatedStandardBucketCharge(i),
newStats.getAccumulatedStandardBucketCharge(i));
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(stats.getAccumulatedCustomBucketCharge(i),
newStats.getAccumulatedCustomBucketCharge(i));
}
assertEquals(POWER_DATA_UNAVAILABLE,
- newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
+ newStats.getAccumulatedCustomBucketCharge(customBucketNames.length + 1));
parcel.recycle();
}
@Test
public void testCreateAndReadSummaryFromParcel() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -166,25 +169,25 @@ public class MeasuredEnergyStatsTest {
assertEquals(stats.getAccumulatedStandardBucketCharge(i),
newStats.getAccumulatedStandardBucketCharge(i));
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(stats.getAccumulatedCustomBucketCharge(i),
newStats.getAccumulatedCustomBucketCharge(i));
}
assertEquals(POWER_DATA_UNAVAILABLE,
- newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
+ newStats.getAccumulatedCustomBucketCharge(customBucketNames.length + 1));
parcel.recycle();
}
@Test
public void testCreateAndReadSummaryFromParcel_existingTemplate() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats template =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -205,7 +208,7 @@ public class MeasuredEnergyStatsTest {
newsupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true
newsupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false
final MeasuredEnergyStats newTemplate =
- new MeasuredEnergyStats(newsupportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(newsupportedStandardBuckets, customBucketNames);
parcel.setDataPosition(0);
final MeasuredEnergyStats newStats =
@@ -225,23 +228,23 @@ public class MeasuredEnergyStatsTest {
newStats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(stats.getAccumulatedCustomBucketCharge(i),
newStats.getAccumulatedCustomBucketCharge(i));
}
assertEquals(POWER_DATA_UNAVAILABLE,
- newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
+ newStats.getAccumulatedCustomBucketCharge(customBucketNames.length + 1));
parcel.recycle();
}
@Test
public void testCreateAndReadSummaryFromParcel_skipZero() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
Arrays.fill(supportedStandardBuckets, true);
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
// Accumulate charge in one bucket and one custom bucket, the rest should be zero
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 200);
stats.updateCustomBucket(1, 60);
@@ -298,13 +301,13 @@ public class MeasuredEnergyStatsTest {
@Test
public void testCreateAndReadSummaryFromParcel_nullTemplate() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -324,13 +327,13 @@ public class MeasuredEnergyStatsTest {
@Test
public void testCreateAndReadSummaryFromParcel_boring() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats template =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -348,7 +351,7 @@ public class MeasuredEnergyStatsTest {
newSupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true
newSupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false
final MeasuredEnergyStats newTemplate =
- new MeasuredEnergyStats(newSupportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(newSupportedStandardBuckets, customBucketNames);
parcel.setDataPosition(0);
final MeasuredEnergyStats newStats =
@@ -362,13 +365,13 @@ public class MeasuredEnergyStatsTest {
@Test
public void testUpdateBucket() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_DOZE, 30);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -389,7 +392,8 @@ public class MeasuredEnergyStatsTest {
@Test
public void testIsValidCustomBucket() {
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3);
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS],
+ new String[]{"A", "B", "C"});
assertFalse(stats.isValidCustomBucket(-1));
assertTrue(stats.isValidCustomBucket(0));
assertTrue(stats.isValidCustomBucket(1));
@@ -398,7 +402,7 @@ public class MeasuredEnergyStatsTest {
assertFalse(stats.isValidCustomBucket(4));
final MeasuredEnergyStats boringStats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0);
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[0]);
assertFalse(boringStats.isValidCustomBucket(-1));
assertFalse(boringStats.isValidCustomBucket(0));
assertFalse(boringStats.isValidCustomBucket(1));
@@ -407,8 +411,8 @@ public class MeasuredEnergyStatsTest {
@Test
public void testGetAccumulatedCustomBucketCharges() {
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3);
-
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS],
+ new String[]{"A", "B", "C"});
stats.updateCustomBucket(0, 50);
stats.updateCustomBucket(1, 60);
stats.updateCustomBucket(2, 13);
@@ -425,7 +429,7 @@ public class MeasuredEnergyStatsTest {
@Test
public void testGetAccumulatedCustomBucketCharges_empty() {
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0);
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[0]);
final long[] output = stats.getAccumulatedCustomBucketCharges();
assertEquals(0, output.length);
@@ -433,22 +437,23 @@ public class MeasuredEnergyStatsTest {
@Test
public void testGetNumberCustomChargeBuckets() {
- assertEquals(0, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0)
- .getNumberCustomPowerBuckets());
- assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3)
- .getNumberCustomPowerBuckets());
+ assertEquals(0,
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[0])
+ .getNumberCustomPowerBuckets());
+ assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS],
+ new String[]{"A", "B", "C"}).getNumberCustomPowerBuckets());
}
@Test
public void testReset() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -466,7 +471,7 @@ public class MeasuredEnergyStatsTest {
assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(0, stats.getAccumulatedCustomBucketCharge(i));
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2fe8b285ed88..5f344267d71c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -348,6 +348,8 @@ applications that come with the platform
<permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
<permission name="android.permission.INSTALL_PACKAGES"/>
<!-- Needed for test only -->
+ <permission name="android.permission.ACCESS_MTP"/>
+ <!-- Needed for test only -->
<permission name="android.permission.INTERACT_ACROSS_PROFILES"/>
<!-- Permission required to test onPermissionsChangedListener -->
<permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
@@ -404,6 +406,7 @@ applications that come with the platform
<permission name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" />
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
+ <permission name="android.permission.UWB_PRIVILEGED"/>
<permission name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index fec78f070311..81f1021c6eab 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1825,6 +1825,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
},
+ "35398067": {
+ "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+ "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+ },
"38267433": {
"message": "Attempted to reset replacing window on non-existing app token %s",
"level": "WARN",
diff --git a/libs/WindowManager/Shell/res/drawable/pip_menu_background.xml b/libs/WindowManager/Shell/res/drawable/pip_menu_background.xml
new file mode 100644
index 000000000000..29907a61b4cc
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_menu_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#FF000000"/>
+
+ <corners android:radius="@dimen/pip_corner_radius" />
+</shape> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 11c146457844..dca598518432 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -739,14 +739,11 @@ public class BubbleController {
return (isSummary && isSuppressedSummary) || isSuppressedBubble;
}
- private void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
- Executor callbackExecutor) {
+ private void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback) {
if (mBubbleData.isSummarySuppressed(groupKey)) {
mBubbleData.removeSuppressedSummary(groupKey);
if (callback != null) {
- callbackExecutor.execute(() -> {
- callback.accept(mBubbleData.getSummaryKey(groupKey));
- });
+ callback.accept(mBubbleData.getSummaryKey(groupKey));
}
}
}
@@ -1298,8 +1295,10 @@ public class BubbleController {
public void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
Executor callbackExecutor) {
mMainExecutor.execute(() -> {
- BubbleController.this.removeSuppressedSummaryIfNecessary(groupKey, callback,
- callbackExecutor);
+ Consumer<String> cb = callback != null
+ ? (key) -> callbackExecutor.execute(() -> callback.accept(key))
+ : null;
+ BubbleController.this.removeSuppressedSummaryIfNecessary(groupKey, cb);
});
}
@@ -1340,10 +1339,13 @@ public class BubbleController {
@Override
public boolean handleDismissalInterception(BubbleEntry entry,
- @Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
+ @Nullable List<BubbleEntry> children, IntConsumer removeCallback,
+ Executor callbackExecutor) {
+ IntConsumer cb = removeCallback != null
+ ? (index) -> callbackExecutor.execute(() -> removeCallback.accept(index))
+ : null;
return mMainExecutor.executeBlockingForResult(() -> {
- return BubbleController.this.handleDismissalInterception(entry, children,
- removeCallback);
+ return BubbleController.this.handleDismissalInterception(entry, children, cb);
}, Boolean.class);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 9fc8aef47064..1bfb61929297 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -140,7 +140,7 @@ public interface Bubbles {
* @return true if we want to intercept the dismissal of the entry, else false.
*/
boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
- IntConsumer removeCallback);
+ IntConsumer removeCallback, Executor callbackExecutor);
/** Set the proxy to commnuicate with SysUi side components. */
void setSysuiProxy(SysuiProxy proxy);
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 5c3af3ee5330..8ac9a7a479db 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
@@ -37,6 +37,7 @@ import com.android.wm.shell.animation.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Controller class of PiP animations (both from and to PiP mode).
@@ -112,6 +113,7 @@ public class PipAnimationController {
PipTransitionAnimator.ofAlpha(taskInfo, leash, destinationBounds, alphaStart,
alphaEnd));
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
+ && Objects.equals(destinationBounds, mCurrentAnimator.getDestinationBounds())
&& mCurrentAnimator.isRunning()) {
mCurrentAnimator.updateEndValue(alphaEnd);
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
index 3af0ff0dfb36..d4f229cb3e09 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
@@ -216,7 +216,7 @@ public class PipMediaController {
}
ArrayList<RemoteAction> mediaActions = new ArrayList<>();
- boolean isPlaying = mMediaController.getPlaybackState().isActiveState();
+ boolean isPlaying = mMediaController.getPlaybackState().isActive();
long actions = mMediaController.getPlaybackState().getActions();
// Prev action
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 e152633063be..e66be66c8ef4 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
@@ -99,9 +99,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private enum State {
UNDEFINED(0),
TASK_APPEARED(1),
- ENTERING_PIP(2),
- ENTERED_PIP(3),
- EXITING_PIP(4);
+ ENTRY_SCHEDULED(2),
+ ENTERING_PIP(3),
+ ENTERED_PIP(4),
+ EXITING_PIP(5);
private final int mStateValue;
@@ -265,6 +266,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
+ * Returns whether the entry animation is waiting to be started.
+ */
+ public boolean isEntryScheduled() {
+ return mState == State.ENTRY_SCHEDULED;
+ }
+
+ /**
* Registers a callback when a display change has been detected when we enter PiP.
*/
public void registerOnDisplayIdChangeCallback(IntConsumer onDisplayIdChangeCallback) {
@@ -492,6 +500,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}
+ /**
+ * Called when the display rotation handling is skipped (e.g. when rotation happens while in
+ * the middle of an entry transition).
+ */
+ public void onDisplayRotationSkipped() {
+ if (isEntryScheduled()) {
+ // The PIP animation is scheduled to start with the previous orientation's bounds,
+ // re-calculate the entry bounds and restart the alpha animation.
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+ enterPipWithAlphaAnimation(destinationBounds, mEnterAnimationDuration);
+ }
+ }
+
@VisibleForTesting
void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) {
// If we are fading the PIP in, then we should move the pip to the final location as
@@ -501,6 +522,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceControlTransactionFactory.getTransaction();
tx.setAlpha(mLeash, 0f);
tx.apply();
+ mState = State.ENTRY_SCHEDULED;
applyEnterPipSyncTransaction(destinationBounds, () -> {
mPipAnimationController
.getAnimator(mTaskInfo, mLeash, destinationBounds, 0f, 1f)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 62ae1d5d600c..f505e60de61e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -116,7 +116,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
if (!mPipTaskOrganizer.isInPip()
|| mPipBoundsState.getDisplayLayout().rotation() == toRotation
- || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
+ || mPipTaskOrganizer.isDeferringEnterPipAnimation()
+ || mPipTaskOrganizer.isEntryScheduled()) {
// Skip if the same rotation has been set or we aren't in PIP or haven't actually
// entered PIP yet. We still need to update the display layout in the bounds handler
// in this case.
@@ -124,6 +125,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
// do not forget to update the movement bounds as well.
updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
+ mPipTaskOrganizer.onDisplayRotationSkipped();
return;
}
// If there is an animation running (ie. from a shelf offset), then ensure that we calculate
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 7e594a43a52f..3c25a13e94eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -130,7 +130,11 @@ public class PipMenuView extends FrameLayout {
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
inflate(context, R.layout.pip_menu, this);
- mBackgroundDrawable = new ColorDrawable(Color.BLACK);
+ final boolean enableCornerRadius = mContext.getResources()
+ .getBoolean(R.bool.config_pipEnableRoundCorner);
+ mBackgroundDrawable = enableCornerRadius
+ ? mContext.getDrawable(R.drawable.pip_menu_background)
+ : new ColorDrawable(Color.BLACK);
mBackgroundDrawable.setAlpha(0);
mViewRoot = findViewById(R.id.background);
mViewRoot.setBackground(mBackgroundDrawable);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index 98ce2747d532..1f9ff4ab5638 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -89,6 +89,12 @@ class AppPairsTestCannotPairNonResizeableApps(
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
@Presubmit
@Test
fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index ef68ed630353..87ad8de98702 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -103,6 +103,12 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index d341bb1e6aa9..a9881485a3c9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -60,6 +60,12 @@ class RotateTwoLaunchedAppsInAppPairsMode(
}
}
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
@Presubmit
@Test
fun bothAppWindowsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index 3bf0296fee20..3396b90f3083 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -74,6 +74,12 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
@Test
override fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
@Presubmit
@Test
fun bothAppWindowsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index 83853e61ab5e..512fd9a58ea8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -17,11 +17,13 @@
package com.android.wm.shell.flicker.apppairs
import android.view.Surface
+import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.Test
abstract class RotateTwoLaunchedAppsTransition(
testSpec: FlickerTestParameter
@@ -49,4 +51,16 @@ abstract class RotateTwoLaunchedAppsTransition(
}
}
}
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index bca257646e11..e50bde2eaeaa 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -23,7 +23,7 @@ import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.WALLPAPER_TITLE
+import com.android.server.wm.flicker.LAUNCHER_TITLE
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -60,9 +60,9 @@ class EnterSplitScreenDockActivity(
}
override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME, WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME,
+ get() = listOf(LAUNCHER_PACKAGE_NAME, LIVE_WALLPAPER_PACKAGE_NAME,
splitScreenApp.defaultWindowName, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, *LAUNCHER_TITLE)
@FlakyTest(bugId = 169271943)
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index 9717709852d4..64cc85340a38 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -84,7 +84,7 @@ class ExitLegacySplitScreenFromBottom(
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesInVisible() =
testSpec.appWindowBecomesInVisible(secondaryApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index 3f714bb6b6c9..2e115518721f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -78,7 +78,7 @@ class ExitPrimarySplitScreenShowSecondaryFullscreen(
@Test
fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
@@ -87,7 +87,7 @@ class ExitPrimarySplitScreenShowSecondaryFullscreen(
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesInVisible() =
testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 72d6f569ab0c..39f4ce298ff5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -118,7 +118,7 @@ class LegacySplitScreenToLauncher(
fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
- @Presubmit
+ @FlakyTest
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index 8f15e5088914..7cf30ec116eb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -70,7 +70,7 @@ class OpenAppToLegacySplitScreen(
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(splitScreenApp.getPackage())
@@ -86,7 +86,7 @@ class OpenAppToLegacySplitScreen(
@Test
fun appPairsDividerBecomesVisible() = testSpec.appPairsDividerBecomesVisible()
- @Presubmit
+ @FlakyTest
@Test
fun layerBecomesVisible() = testSpec.layerBecomesVisible(splitScreenApp.getPackage())
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index c914adae2b7c..4a59c62ce5d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -92,7 +92,7 @@ class RotateOneLaunchedAppAndEnterSplitScreen(
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() =
testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index ffb20a4bc99a..834821b4825e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -89,7 +89,7 @@ class RotateOneLaunchedAppInSplitScreenMode(
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() =
testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index 9c798d8ea661..db709a078b70 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -98,7 +98,7 @@ class RotateTwoLaunchedAppInSplitScreenMode(
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
testSpec.config.endRotation)
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() =
testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index cd20ddee04fc..2609258e48e0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -54,7 +55,7 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
}
}
- @Presubmit
+ @FlakyTest
@Test
fun pipLayerBecomesVisible() {
testSpec.assertLayers {
@@ -62,7 +63,7 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
}
}
- @Presubmit
+ @FlakyTest
@Test
fun pipWindowBecomesVisible() {
testSpec.assertWm {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 2beec2e8c1ed..33ddec376594 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -88,6 +88,12 @@ class EnterPipToOtherOrientationTest(
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
@Presubmit
@Test
fun pipAppWindowIsAlwaysOnTop() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
index 0408421c72a5..f290b907d2d3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
@@ -16,11 +16,13 @@
package com.android.wm.shell.flicker.pip
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -41,4 +43,16 @@ class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTr
pipApp.closePipWindow(wmHelper)
}
}
+
+ @FlakyTest
+ @Test
+ override fun pipLayerBecomesInvisible() {
+ super.pipLayerBecomesInvisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun pipWindowBecomesInvisible() {
+ super.pipWindowBecomesInvisible()
+ }
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
index c7a1c9aac86b..444026208ec1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -67,11 +68,11 @@ class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition
@Test
override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 852ee4726080..0d686f514116 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -75,7 +76,7 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec)
override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
testSpec.config.endRotation, allStates = false)
- @Presubmit
+ @FlakyTest
@Test
override fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index 6f17a2c57ffc..f7f658e52c52 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -59,7 +58,7 @@ class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
}
}
- @Presubmit
+ @FlakyTest
@Test
fun appReplacesPipWindow() {
testSpec.assertWm {
@@ -69,7 +68,7 @@ class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
}
}
- @Presubmit
+ @FlakyTest
@Test
fun appReplacesPipLayer() {
testSpec.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index ad1ccbd10753..b4c75a6d1165 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -20,6 +20,7 @@ import android.app.Instrumentation
import android.content.Intent
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -167,11 +168,11 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
@Test
open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 9aab7f30e6f8..1e7d08bfc0ed 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -125,6 +125,12 @@ class SetRequestedOrientationWhilePinnedTest(
}
}
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b2a986361b87..24821888e2eb 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -658,10 +658,14 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* cont
if (gpuCompleteTime == -1) {
gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted);
}
- if (gpuCompleteTime < frameInfo->get(FrameInfoIndex::SwapBuffers)) {
- // TODO (b/180488606): Investigate why this can happen for first frames.
- ALOGW("Impossible GPU complete time swapBuffers=%" PRIi64 " gpuComplete=%" PRIi64,
- frameInfo->get(FrameInfoIndex::SwapBuffers), gpuCompleteTime);
+ if (gpuCompleteTime < frameInfo->get(FrameInfoIndex::IssueDrawCommandsStart)) {
+ // On Vulkan the GPU commands are flushed to the GPU during IssueDrawCommands rather
+ // than after SwapBuffers. So if the GPU signals before issue draw commands, then
+ // something probably went wrong. Anything after that could just be expected
+ // pipeline differences
+ ALOGW("Impossible GPU complete time issueCommandsStart=%" PRIi64
+ " gpuComplete=%" PRIi64,
+ frameInfo->get(FrameInfoIndex::IssueDrawCommandsStart), gpuCompleteTime);
gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted);
}
frameInfo->set(FrameInfoIndex::FrameCompleted) = gpuCompleteTime;
diff --git a/libs/hwui/tests/scripts/skp-capture.sh b/libs/hwui/tests/scripts/skp-capture.sh
index 4b46fbf86818..0749a8dcebcb 100755
--- a/libs/hwui/tests/scripts/skp-capture.sh
+++ b/libs/hwui/tests/scripts/skp-capture.sh
@@ -76,8 +76,8 @@ banner '...WAITING FOR APP INTERACTION...'
# so we continue to show the "waiting for app interaction" message as long as the app still requires
# interaction to draw more frames.
adb_test_file_nonzero() {
- # grab first byte of `du` output
- X="$(adb shell "du \"$1\" 2> /dev/null | dd bs=1 count=1 2> /dev/null")"
+ # grab first byte of `wc -c` output
+ X="$(adb shell "wc -c \"$1\" 2> /dev/null | dd bs=1 count=1 2> /dev/null")"
test "$X" && test "$X" -ne 0
}
timeout=$(( $(date +%s) + $phase1_timeout_seconds))
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 864350e25929..3a19b136b06e 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -2495,7 +2495,10 @@ public final class MediaDrm implements AutoCloseable {
* The default security level is defined as the highest security level
* supported on the device.
*
- * @param mime The mime type of the media data
+ * @param mime The mime type of the media data. Please use {@link
+ * #isCryptoSchemeSupported(UUID, String)} to query mime type support separately;
+ * for unsupported mime types the return value of {@link
+ * #requiresSecureDecoder(String)} is crypto scheme dependent.
*/
public boolean requiresSecureDecoder(@NonNull String mime) {
return requiresSecureDecoder(mime, getMaxSecurityLevel());
@@ -2505,7 +2508,10 @@ public final class MediaDrm implements AutoCloseable {
* Query if the crypto scheme requires the use of a secure decoder
* to decode data of the given mime type at the given security level.
*
- * @param mime The mime type of the media data
+ * @param mime The mime type of the media data. Please use {@link
+ * #isCryptoSchemeSupported(UUID, String, int)} to query mime type support
+ * separately; for unsupported mime types the return value of {@link
+ * #requiresSecureDecoder(String, int)} is crypto scheme dependent.
* @param level a security level between {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO}
* and {@link #SECURITY_LEVEL_HW_SECURE_ALL}. Otherwise the special value
* {@link #getMaxSecurityLevel()} is also permitted;
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index e7d30ebba4b1..9eacc74843f9 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -19,7 +19,6 @@ import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.LongDef;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -493,15 +492,26 @@ public final class PlaybackState implements Parcelable {
/**
* Returns whether this is considered as an active playback state.
- * @hide
+ * <p>
+ * The playback state is considered as an active if the state is one of the following:
+ * <ul>
+ * <li>{@link #STATE_BUFFERING}</li>
+ * <li>{@link #STATE_CONNECTING}</li>
+ * <li>{@link #STATE_FAST_FORWARDING}</li>
+ * <li>{@link #STATE_PLAYING}</li>
+ * <li>{@link #STATE_REWINDING}</li>
+ * <li>{@link #STATE_SKIPPING_TO_NEXT}</li>
+ * <li>{@link #STATE_SKIPPING_TO_PREVIOUS}</li>
+ * <li>{@link #STATE_SKIPPING_TO_QUEUE_ITEM}</li>
+ * </ul>
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public boolean isActiveState() {
+ public boolean isActive() {
switch (mState) {
case PlaybackState.STATE_FAST_FORWARDING:
case PlaybackState.STATE_REWINDING:
case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
case PlaybackState.STATE_SKIPPING_TO_NEXT:
+ case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
case PlaybackState.STATE_BUFFERING:
case PlaybackState.STATE_CONNECTING:
case PlaybackState.STATE_PLAYING:
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 63e0fe945abb..2194575f20ba 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -239,6 +239,7 @@ package android.net {
method public final void sendQosSessionLost(int, int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method @Deprecated public void setLegacySubtype(int, @NonNull String);
+ method public void setLingerDuration(@NonNull java.time.Duration);
method public void setTeardownDelayMs(@IntRange(from=0, to=0x1388) int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
index 26cb1ed6b4b4..9a58add5d2ba 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -42,4 +42,5 @@ oneway interface INetworkAgentRegistry {
void sendQosSessionLost(int qosCallbackId, in QosSession session);
void sendQosCallbackError(int qosCallbackId, int exceptionType);
void sendTeardownDelayMs(int teardownDelayMs);
+ void sendLingerDuration(int durationMs);
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index 3622c1c669db..518d3f39d113 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
@@ -106,6 +107,9 @@ public abstract class NetworkAgent {
private final String LOG_TAG;
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ /** @hide */
+ @TestApi
+ public static final int MIN_LINGER_TIMER_MS = 2000;
private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>();
private volatile long mLastBwRefreshTime = 0;
private static final long BW_REFRESH_MIN_WIN_MS = 500;
@@ -391,6 +395,15 @@ public abstract class NetworkAgent {
*/
public static final int CMD_NETWORK_DESTROYED = BASE + 23;
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to set the linger duration for this network
+ * agent.
+ * arg1 = the linger duration, represents by {@link Duration}.
+ *
+ * @hide
+ */
+ public static final int EVENT_LINGER_DURATION_CHANGED = BASE + 24;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
config.legacyTypeName, config.legacySubTypeName);
@@ -1287,6 +1300,22 @@ public abstract class NetworkAgent {
queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
}
+ /**
+ * Set the linger duration for this network agent.
+ * @param duration the delay between the moment the network becomes unneeded and the
+ * moment the network is disconnected or moved into the background.
+ * Note that If this duration has greater than millisecond precision, then
+ * the internal implementation will drop any excess precision.
+ */
+ public void setLingerDuration(@NonNull final Duration duration) {
+ Objects.requireNonNull(duration);
+ final long durationMs = duration.toMillis();
+ if (durationMs < MIN_LINGER_TIMER_MS || durationMs > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("Duration must be within ["
+ + MIN_LINGER_TIMER_MS + "," + Integer.MAX_VALUE + "]ms");
+ }
+ queueOrSendMessage(ra -> ra.sendLingerDuration((int) durationMs));
+ }
/** @hide */
protected void log(final String s) {
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index ba83a44d0d6c..efd336377114 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.net.NetworkCapabilities.RedactionType;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -45,7 +46,7 @@ public final class VpnTransportInfo implements TransportInfo, Parcelable {
public final String sessionId;
@Override
- public long getApplicableRedactions() {
+ public @RedactionType long getApplicableRedactions() {
return REDACT_FOR_NETWORK_SETTINGS;
}
@@ -53,7 +54,7 @@ public final class VpnTransportInfo implements TransportInfo, Parcelable {
* Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
*/
@NonNull
- public VpnTransportInfo makeCopy(long redactions) {
+ public VpnTransportInfo makeCopy(@RedactionType long redactions) {
return new VpnTransportInfo(type,
((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : sessionId);
}
diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml b/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
index dcbdc07d1335..cec8b3294418 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
<resources>
- <!--DEPRECATED. It will remove after all of client team migrated to new style. -->
+ <!--DEPRECATED. It will be removed after all of client teams migrated to new style. -->
<style name="PreferenceTheme" parent="@style/PreferenceThemeOverlay">
<item name="preferenceCategoryStyle">@style/SettingsCategoryPreference</item>
<item name="preferenceStyle">@style/SettingsPreference</item>
@@ -28,7 +28,7 @@
<item name="footerPreferenceStyle">@style/Preference.Material</item>
</style>
- <style name="SettingsPreferenceTheme" parent="@style/PreferenceThemeOverlay">
+ <style name="PreferenceTheme.SettingsBase" parent="@style/PreferenceThemeOverlay">
<item name="preferenceCategoryStyle">@style/SettingsCategoryPreference</item>
<item name="preferenceStyle">@style/SettingsPreference</item>
<item name="checkBoxPreferenceStyle">@style/SettingsCheckBoxPreference</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/themes.xml b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
index 13c7523317fe..9c096d28c5c8 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
@@ -21,7 +21,7 @@
<item name="android:textAppearanceListItem">@style/TextAppearance.PreferenceTitle</item>
<item name="android:listPreferredItemPaddingStart">@dimen/preference_padding_start</item>
<item name="android:listPreferredItemPaddingEnd">@dimen/preference_padding_end</item>
- <item name="preferenceTheme">@style/SettingsPreferenceTheme</item>
+ <item name="preferenceTheme">@style/PreferenceTheme.SettingsBase</item>
</style>
<!-- Using in SubSettings page including injected settings page -->
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bef6423f3baa..f685d888ffa3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -113,6 +113,8 @@
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<!-- ACCESS_BACKGROUND_LOCATION is needed for testing purposes only. -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <!-- ACCESS_MTP is needed for testing purposes only. -->
+ <uses-permission android:name="android.permission.ACCESS_MTP" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -539,6 +541,9 @@
<!-- Permission required for CTS test - CtsRotationResolverServiceDeviceTestCases -->
<uses-permission android:name="android.permission.MANAGE_ROTATION_RESOLVER" />
+ <!-- Permission required for CTS test - CtsUwbTestCases -->
+ <uses-permission android:name="android.permission.UWB_PRIVILEGED" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
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 da78a7c24d0f..3363f8ea808c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -313,12 +313,14 @@ class ActivityLaunchAnimator(context: Context) {
}
context.mainExecutor.execute {
- startAnimation(remoteAnimationTargets, iRemoteAnimationFinishedCallback)
+ startAnimation(remoteAnimationTargets, remoteAnimationNonAppTargets,
+ iRemoteAnimationFinishedCallback)
}
}
private fun startAnimation(
remoteAnimationTargets: Array<out RemoteAnimationTarget>,
+ remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
iCallback: IRemoteAnimationFinishedCallback
) {
val window = remoteAnimationTargets.firstOrNull {
@@ -332,7 +334,7 @@ class ActivityLaunchAnimator(context: Context) {
return
}
- val navigationBar = remoteAnimationTargets.firstOrNull {
+ val navigationBar = remoteAnimationNonAppTargets.firstOrNull {
it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
}
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 35423a979cbc..53ff9f0e8c0b 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
@@ -58,5 +58,7 @@ public interface BcSmartspaceDataPlugin extends Plugin {
/** View to which this plugin can be registered, in order to get updates. */
interface SmartspaceView {
void registerDataProvider(BcSmartspaceDataPlugin plugin);
+
+ void setPrimaryTextColor(int color);
}
}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 00c27bf5f10d..1cef44b3b3df 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -79,7 +79,6 @@
android:id="@+id/left_aligned_notification_icon_container"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_shelf_height"
- android:layout_marginTop="@dimen/widget_vertical_padding"
android:layout_below="@id/keyguard_status_area"
android:paddingStart="@dimen/below_clock_padding_start"
/>
diff --git a/packages/SystemUI/res/drawable/qs_detail_background.xml b/packages/SystemUI/res/drawable/qs_detail_background.xml
index 76045e4126cb..e5c7352807f8 100644
--- a/packages/SystemUI/res/drawable/qs_detail_background.xml
+++ b/packages/SystemUI/res/drawable/qs_detail_background.xml
@@ -18,7 +18,7 @@ Copyright (C) 2014 The Android Open Source Project
<inset>
<shape>
<solid android:color="@color/qs_detail_transition"/>
- <corners android:radius="?android:attr/dialogCornerRadius" />
+ <corners android:radius="@dimen/qs_footer_action_corner_radius" />
</shape>
</inset>
</item>
@@ -26,7 +26,7 @@ Copyright (C) 2014 The Android Open Source Project
<inset>
<shape>
<solid android:color="?android:attr/colorBackgroundFloating"/>
- <corners android:radius="?android:attr/dialogCornerRadius" />
+ <corners android:radius="@dimen/qs_footer_action_corner_radius" />
</shape>
</inset>
</item>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml b/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
index 34675ab891c1..6022206c208c 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
@@ -23,14 +23,14 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/qs_footer_action_border"/>
<solid android:color="@android:color/transparent"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml b/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml
index 596ed711dd43..bbcfb15d9226 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml
@@ -22,13 +22,13 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/transparent"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2355650907df..ac41a250d4e2 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -656,4 +656,10 @@
<!-- Y -->
<!-- radius -->
</integer-array>
+
+ <!-- Overrides the behavior of the face unlock keyguard bypass setting:
+ 0 - Don't override the setting (default)
+ 1 - Override the setting to always bypass keyguard
+ 2 - Override the setting to never bypass keyguard -->
+ <integer name="config_face_unlock_bypass_override">0</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a19d128a9c67..5767174ba603 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -412,6 +412,8 @@
<!-- The size of each of the icon buttons in the QS footer -->
<dimen name="qs_footer_action_button_size">@dimen/qs_footer_height</dimen>
+ <dimen name="qs_footer_action_corner_radius">20dp</dimen>
+
<!-- (48dp - 44dp) / 2 -->
<dimen name="qs_footer_action_inset">2dp</dimen>
@@ -1413,17 +1415,17 @@
<dimen name="accessibility_floating_menu_large_single_radius">33dp</dimen>
<dimen name="accessibility_floating_menu_large_multiple_radius">35dp</dimen>
- <dimen name="rounded_slider_height">44dp</dimen>
+ <dimen name="rounded_slider_height">48dp</dimen>
<!-- rounded_slider_height / 2 -->
- <dimen name="rounded_slider_corner_radius">22dp</dimen>
+ <dimen name="rounded_slider_corner_radius">24dp</dimen>
<dimen name="rounded_slider_icon_size">20dp</dimen>
<!-- (rounded_slider_height - rounded_slider_icon_size) / 2 -->
- <dimen name="rounded_slider_icon_inset">12dp</dimen>
+ <dimen name="rounded_slider_icon_inset">14dp</dimen>
<!-- rounded_slider_corner_radius - rounded_slider_track_corner_radius -->
- <dimen name="rounded_slider_track_inset">18dp</dimen>
- <dimen name="rounded_slider_track_width">8dp</dimen>
+ <dimen name="rounded_slider_track_inset">22dp</dimen>
+ <dimen name="rounded_slider_track_width">4dp</dimen>
<!-- rounded_slider_track_width / 2 -->
- <dimen name="rounded_slider_track_corner_radius">4dp</dimen>
+ <dimen name="rounded_slider_track_corner_radius">2dp</dimen>
<!-- inset for ic_lock_open within a DisabledUdfpsView -->
<dimen name="udfps_unlock_icon_inset">16dp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index af3239e6beb1..1e98f866bd4e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -79,11 +79,6 @@ interface ISystemUiProxy {
void startAssistant(in Bundle bundle) = 13;
/**
- * Creates a new gesture monitor
- */
- Bundle monitorGestureInput(String name, int displayId) = 14;
-
- /**
* Notifies that the accessibility button in the system's navigation area has been clicked
*/
void notifyAccessibilityButtonClicked(int displayId) = 15;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java
index 074448d963b1..bf8e6a5663c0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java
@@ -16,10 +16,7 @@
package com.android.systemui.shared.system;
import android.hardware.input.InputManager;
-import android.os.Bundle;
import android.os.Looper;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.view.Choreographer;
import android.view.InputMonitor;
@@ -29,9 +26,8 @@ import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
/**
* @see android.view.InputMonitor
*/
-public class InputMonitorCompat implements Parcelable {
+public class InputMonitorCompat {
private final InputMonitor mInputMonitor;
- private boolean mForReturn = false;
/**
* Monitor input on the specified display for gestures.
@@ -40,10 +36,6 @@ public class InputMonitorCompat implements Parcelable {
mInputMonitor = InputManager.getInstance().monitorGestureInput(name, displayId);
}
- private InputMonitorCompat(InputMonitor monitor) {
- mInputMonitor = monitor;
- }
-
/**
* @see InputMonitor#pilferPointers()
*/
@@ -66,48 +58,4 @@ public class InputMonitorCompat implements Parcelable {
return new InputEventReceiver(mInputMonitor.getInputChannel(), looper, choreographer,
listener);
}
-
- /**
- * Gets the input monitor stored in a bundle
- */
- public static InputMonitorCompat fromBundle(Bundle bundle, String key) {
- bundle.setClassLoader(InputMonitorCompat.class.getClassLoader());
- return (InputMonitorCompat) bundle.getParcelable(key);
- }
-
- /**
- * Gets the input monitor compat as the return value.
- */
- public static InputMonitorCompat obtainReturnValue(InputMonitor monitor) {
- final InputMonitorCompat monitorCompat = new InputMonitorCompat(monitor);
- monitorCompat.mForReturn = true;
- return monitorCompat;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- mInputMonitor.writeToParcel(dest,
- mForReturn ? PARCELABLE_WRITE_RETURN_VALUE : flags);
- }
-
- private InputMonitorCompat(Parcel in) {
- mInputMonitor = InputMonitor.CREATOR.createFromParcel(in);
- }
-
- public static final Creator<InputMonitorCompat> CREATOR = new Creator<InputMonitorCompat>() {
- @Override
- public InputMonitorCompat createFromParcel(Parcel in) {
- return new InputMonitorCompat(in);
- }
-
- @Override
- public InputMonitorCompat[] newArray(int size) {
- return new InputMonitorCompat[size];
- }
- };
}
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 41840afc4995..927bce08268d 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
@@ -38,7 +38,6 @@ import java.util.StringJoiner;
public class QuickStepContract {
public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
- public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor";
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
// See IPip.aidl
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 032ed7da0a46..f89e365bc995 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -26,14 +26,18 @@ import android.app.smartspace.SmartspaceSession;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Color;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.graphics.ColorUtils;
import com.android.keyguard.clock.ClockManager;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -50,6 +54,7 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import java.util.Locale;
@@ -87,6 +92,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private Executor mUiExecutor;
private SmartspaceSession mSmartspaceSession;
private SmartspaceSession.Callback mSmartspaceCallback;
+ private float mDozeAmount;
+ private int mWallpaperTextColor;
+ private int mDozeColor = Color.WHITE;
+ private ConfigurationController mConfigurationController;
/**
* Listener for changes to the color palette.
@@ -103,8 +112,25 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
};
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onThemeChanged() {
+ updateWallpaperColor();
+ }
+ };
+
private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
+ private final StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ mDozeAmount = eased;
+ updateSmartspaceColor();
+ }
+ };
+
// If set, will replace keyguard_status_area
private BcSmartspaceDataPlugin.SmartspaceView mSmartspaceView;
@@ -121,7 +147,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
PluginManager pluginManager,
FeatureFlags featureFlags,
@Main Executor uiExecutor,
- BatteryController batteryController) {
+ BatteryController batteryController,
+ ConfigurationController configurationController) {
super(keyguardClockSwitch);
mResources = resources;
mStatusBarStateController = statusBarStateController;
@@ -134,6 +161,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mIsSmartspaceEnabled = featureFlags.isSmartspaceEnabled();
mUiExecutor = uiExecutor;
mBatteryController = batteryController;
+ mConfigurationController = configurationController;
}
/**
@@ -172,6 +200,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mBatteryController);
mLargeClockViewController.init();
+ mDozeAmount = mStatusBarStateController.getDozeAmount();
+ updateWallpaperColor();
+
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mConfigurationController.addCallback(mConfigurationListener);
+
// If a smartspace plugin is detected, replace the existing smartspace
// (keyguard_status_area), and initialize a new session
mPluginListener = new PluginListener<BcSmartspaceDataPlugin>() {
@@ -186,8 +220,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mSmartspaceView = plugin.getView(mView);
mSmartspaceView.registerDataProvider(plugin);
+ updateSmartspaceColor();
View asView = (View) mSmartspaceView;
+ // Place plugin view below normal clock...
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
lp.addRule(RelativeLayout.BELOW, R.id.lockscreen_clock_view);
@@ -197,6 +233,11 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
.getDimensionPixelSize(R.dimen.below_clock_padding_start);
asView.setPadding(padding, 0, padding, 0);
+ // ... but above the large clock
+ lp = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
+ lp.addRule(RelativeLayout.BELOW, asView.getId());
+ mLargeClockFrame.setLayoutParams(lp);
+
View nic = mView.findViewById(
com.android.systemui.R.id.left_aligned_notification_icon_container);
lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
@@ -219,6 +260,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
nic.getLayoutParams();
lp.addRule(RelativeLayout.BELOW, R.id.keyguard_status_area);
nic.setLayoutParams(lp);
+ mLargeClockFrame.setLayoutParams(lp);
mSmartspaceView = null;
}
@@ -235,6 +277,19 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mPluginManager.addPluginListener(mPluginListener, BcSmartspaceDataPlugin.class, false);
}
+ private void updateWallpaperColor() {
+ mWallpaperTextColor = Utils.getColorAttrDefaultColor(getContext(),
+ R.attr.wallpaperTextColor);
+ updateSmartspaceColor();
+ }
+
+ private void updateSmartspaceColor() {
+ if (mSmartspaceView != null) {
+ int color = ColorUtils.blendARGB(mWallpaperTextColor, mDozeColor, mDozeAmount);
+ mSmartspaceView.setPrimaryTextColor(color);
+ }
+ }
+
@Override
protected void onViewDetached() {
if (CUSTOM_CLOCKS_ENABLED) {
@@ -249,6 +304,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mSmartspaceSession = null;
}
mPluginManager.removePluginListener(mPluginListener);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ mConfigurationController.removeCallback(mConfigurationListener);
}
/**
@@ -392,4 +449,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private int getCurrentLayoutDirection() {
return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
}
+
+ @VisibleForTesting
+ ConfigurationController.ConfigurationListener getConfigurationListener() {
+ return mConfigurationListener;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index 8cd68ef8acbc..ab15630a6975 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -18,7 +18,7 @@ data class KeyguardFaceListenModel(
val isFaceDisabled: Boolean,
val isBecauseCannotSkipBouncer: Boolean,
val isKeyguardGoingAway: Boolean,
- val isFaceSettingEnabledForUser: Boolean,
+ val isBiometricSettingEnabledForUser: Boolean,
val isLockIconPressed: Boolean,
val isScanningAllowedByStrongAuth: Boolean,
val isPrimaryUser: Boolean,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 67ee1f45048e..138dd15b33b7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -353,18 +353,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
};
- private SparseBooleanArray mFaceSettingEnabledForUser = new SparseBooleanArray();
+ private SparseBooleanArray mBiometricEnabledForUser = new SparseBooleanArray();
private BiometricManager mBiometricManager;
private IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
new IBiometricEnabledOnKeyguardCallback.Stub() {
@Override
- public void onChanged(BiometricSourceType type, boolean enabled, int userId)
- throws RemoteException {
+ public void onChanged(boolean enabled, int userId) throws RemoteException {
mHandler.post(() -> {
- if (type == BiometricSourceType.FACE) {
- mFaceSettingEnabledForUser.put(userId, enabled);
- updateFaceListeningState();
- }
+ mBiometricEnabledForUser.put(userId, enabled);
+ updateBiometricListeningState();
});
}
};
@@ -1119,6 +1116,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
|| containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
final boolean isEncrypted = containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT);
+
return isEncrypted || isLockDown;
}
@@ -1359,7 +1357,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:AOD_INTERRUPT_END");
}
- mAuthController.onCancelAodInterrupt();
+ mAuthController.onCancelUdfps();
mIsUdfpsRunningWhileDozing = false;
}
};
@@ -1631,6 +1629,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
}
+ @VisibleForTesting
+ void resetBiometricListeningState() {
+ mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+ mFaceRunningState = BIOMETRIC_STATE_STOPPED;
+ }
+
private void registerRingerTracker() {
mRingerModeTracker.getRingerMode().observeForever(mRingerModeObserver);
}
@@ -1951,7 +1955,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mIsFaceEnrolled = whitelistIpcs(
() -> mFaceManager != null && mFaceManager.isHardwareDetected()
&& mFaceManager.hasEnrolledTemplates(userId)
- && mFaceSettingEnabledForUser.get(userId));
+ && mBiometricEnabledForUser.get(userId));
}
/**
@@ -2099,7 +2103,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
shouldListenForFingerprintAssistant() || (mKeyguardOccluded && mIsDreaming))
&& !mSwitchingUser && !isFingerprintDisabled(getCurrentUser())
&& (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser
- && allowedOnBouncer;
+ && allowedOnBouncer && mBiometricEnabledForUser.get(getCurrentUser());
return shouldListen;
}
@@ -2158,7 +2162,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
(mBouncer || mAuthInterruptActive || awakeKeyguard
|| shouldListenForFaceAssistant())
&& !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
- && !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed
+ && !mKeyguardGoingAway && mBiometricEnabledForUser.get(user) && !mLockIconPressed
&& strongAuthAllowsScanning && mIsPrimaryUser
&& !mSecureCameraLaunched;
@@ -2176,7 +2180,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
isFaceDisabled(user),
becauseCannotSkipBouncer,
mKeyguardGoingAway,
- mFaceSettingEnabledForUser.get(user),
+ mBiometricEnabledForUser.get(user),
mLockIconPressed,
strongAuthAllowsScanning,
mIsPrimaryUser,
@@ -3235,6 +3239,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
+ pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
if (isUdfpsEnrolled()) {
pw.println(" shouldListenForUdfps=" + shouldListenForUdfps());
pw.println(" bouncerVisible=" + mBouncer);
@@ -3257,7 +3262,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" possible=" + isUnlockWithFacePossible(userId));
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
- pw.println(" enabledByUser=" + mFaceSettingEnabledForUser.get(userId));
+ pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
pw.println(" mSecureCameraLaunched=" + mSecureCameraLaunched);
}
if (mFaceListenModels != null && !mFaceListenModels.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index ed8f32f31035..0c7b55d6ecbb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -309,18 +309,14 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
}
/**
- * Cancel a fingerprint scan.
- *
- * The sensor that triggers an AOD interrupt for fingerprint doesn't give
- * ACTION_UP/ACTION_CANCEL events, so the scan needs to be cancelled manually. This should be
- * called when authentication either succeeds or fails. Failing to cancel the scan will leave
- * the screen in high brightness mode.
+ * Cancel a fingerprint scan manually. This will get rid of the white circle on the udfps
+ * sensor area even if the user hasn't explicitly lifted their finger yet.
*/
- public void onCancelAodInterrupt() {
+ public void onCancelUdfps() {
if (mUdfpsController == null) {
return;
}
- mUdfpsController.onCancelAodInterrupt();
+ mUdfpsController.onCancelUdfps();
}
private void sendResultAndCleanUp(@DismissedReason int reason,
@@ -499,6 +495,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
mCurrentDialog.onError(errorMessage);
}
+
+ onCancelUdfps();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index aa818bfdadeb..9239a8ade615 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -35,15 +36,23 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
+import android.media.AudioAttributes;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
+import android.view.View;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -94,7 +103,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull private final DumpManager mDumpManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
- @NonNull private FalsingManager mFalsingManager;
+ @NonNull private final Vibrator mVibrator;
+ @NonNull private final Handler mMainHandler;
+ @NonNull private final FalsingManager mFalsingManager;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -118,6 +129,27 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
private boolean mIsAodInterruptActive;
@Nullable private Runnable mCancelAodTimeoutAction;
+ private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
+ new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
+
+ private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ private final VibrationEffect mEffectTextureTick =
+ VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
+ private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ private final VibrationEffect mEffectHeavy =
+ VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
+ private final Runnable mAcquiredVibration = new Runnable() {
+ @Override
+ public void run() {
+ String effect = Settings.Global.getString(mContext.getContentResolver(),
+ "udfps_acquired_type");
+ mVibrator.vibrate(getVibration(effect, mEffectTick), VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+ };
+
/**
* Keeps track of state within a single FingerprintService request. Note that this state
* persists across configuration changes, etc, since it is considered a single request.
@@ -227,7 +259,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
};
@SuppressLint("ClickableViewAccessibility")
- private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> {
+ private final UdfpsView.OnTouchListener mOnTouchListener = this::onTouch;
+
+ private boolean onTouch(View view, MotionEvent event) {
UdfpsView udfpsView = (UdfpsView) view;
final boolean isFingerDown = udfpsView.isIlluminationRequested();
boolean handled = false;
@@ -251,6 +285,27 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
// data for many other pointers because of multi-touch support.
mActivePointerId = event.getPointerId(0);
mVelocityTracker.addMovement(event);
+
+ // TODO: (b/185124905) these settings are for ux testing purposes and should
+ // be removed (or cached) before going into production
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ int startEnabled = Settings.Global.getInt(contentResolver,
+ "udfps_start", 0);
+ if (startEnabled > 0) {
+ String startEffectSetting = Settings.Global.getString(contentResolver,
+ "udfps_start_type");
+ mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick),
+ VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+
+ int acquiredEnabled = Settings.Global.getInt(contentResolver,
+ "udfps_acquired", 0);
+ if (acquiredEnabled > 0) {
+ int delay = Settings.Global.getInt(contentResolver,
+ "udfps_acquired_delay", 500);
+ mMainHandler.removeCallbacks(mAcquiredVibration);
+ mMainHandler.postDelayed(mAcquiredVibration, delay);
+ }
handled = true;
}
break;
@@ -307,7 +362,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
// Do nothing.
}
return handled;
- };
+ }
@Inject
public UdfpsController(@NonNull Context context,
@@ -324,6 +379,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull KeyguardViewMediator keyguardViewMediator,
@NonNull FalsingManager falsingManager) {
mContext = context;
+ // TODO (b/185124905): inject main handler and vibrator once done prototyping
+ mMainHandler = new Handler(Looper.getMainLooper());
+ mVibrator = context.getSystemService(Vibrator.class);
mInflater = inflater;
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
// fingerprint manager should never be null.
@@ -559,19 +617,25 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
// Since the sensor that triggers the AOD interrupt doesn't provide ACTION_UP/ACTION_CANCEL,
// we need to be careful about not letting the screen accidentally remain in high brightness
// mode. As a mitigation, queue a call to cancel the fingerprint scan.
- mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelAodInterrupt,
+ mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps,
AOD_INTERRUPT_TIMEOUT_MILLIS);
// using a hard-coded value for major and minor until it is available from the sensor
onFingerDown(screenX, screenY, minor, major);
}
/**
- * Cancel fingerprint scan.
+ * Cancel updfs scan affordances - ability to hide the HbmSurfaceView (white circle) before
+ * user explicitly lifts their finger. Generally, this should be called whenever udfps fails
+ * or errors.
*
- * This is intended to be called after the fingerprint scan triggered by the AOD interrupt
- * either succeeds or fails.
+ * The sensor that triggers an AOD fingerprint interrupt (see onAodInterrupt) doesn't give
+ * ACTION_UP/ACTION_CANCEL events, so and AOD interrupt scan needs to be cancelled manually.
+ * This should be called when authentication either succeeds or fails. Failing to cancel the
+ * scan will leave the screen in high brightness mode and will show the HbmSurfaceView until
+ * the user lifts their finger.
*/
- void onCancelAodInterrupt() {
+ void onCancelUdfps() {
+ onFingerUp();
if (!mIsAodInterruptActive) {
return;
}
@@ -580,7 +644,6 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
mCancelAodTimeoutAction = null;
}
mIsAodInterruptActive = false;
- onFingerUp();
}
// This method can be called from the UI thread.
@@ -598,6 +661,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
// This method can be called from the UI thread.
private void onFingerUp() {
+ mMainHandler.removeCallbacks(mAcquiredVibration);
if (mView == null) {
Log.w(TAG, "Null view in onFingerUp");
return;
@@ -617,4 +681,23 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
// Do nothing. This method can be implemented for devices that require the high-brightness
// mode for fingerprint illumination.
}
+
+ private VibrationEffect getVibration(String effect, VibrationEffect defaultEffect) {
+ if (TextUtils.isEmpty(effect)) {
+ return defaultEffect;
+ }
+
+ switch (effect.toLowerCase()) {
+ case "click":
+ return mEffectClick;
+ case "heavy":
+ return mEffectHeavy;
+ case "texture_tick":
+ return mEffectTextureTick;
+ case "tick":
+ return mEffectTick;
+ default:
+ return defaultEffect;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 1e86cf1d0171..9d47bbb03380 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -121,6 +121,7 @@ public class WirelessChargingAnimation {
params.setFitInsetsTypes(0 /* ignore all system bar insets */);
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ params.setTrustedOverlay();
if (looper == null) {
// Use Looper.myLooper() if looper is not specified.
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index ce5795ccd339..767d7ab5a490 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -35,12 +35,10 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.GlobalActions;
-import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
@@ -50,18 +48,17 @@ import dagger.Lazy;
public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
private final Context mContext;
- private final Lazy<GlobalActionsDialog> mGlobalActionsDialogLazy;
+ private final Lazy<GlobalActionsDialogLite> mGlobalActionsDialogLazy;
private final KeyguardStateController mKeyguardStateController;
private final DeviceProvisionedController mDeviceProvisionedController;
- private final ExtensionController.Extension<GlobalActionsPanelPlugin> mWalletPluginProvider;
private final BlurUtils mBlurUtils;
private final CommandQueue mCommandQueue;
- private GlobalActionsDialog mGlobalActionsDialog;
+ private GlobalActionsDialogLite mGlobalActionsDialog;
private boolean mDisabled;
@Inject
public GlobalActionsImpl(Context context, CommandQueue commandQueue,
- Lazy<GlobalActionsDialog> globalActionsDialogLazy, BlurUtils blurUtils) {
+ Lazy<GlobalActionsDialogLite> globalActionsDialogLazy, BlurUtils blurUtils) {
mContext = context;
mGlobalActionsDialogLazy = globalActionsDialogLazy;
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
@@ -69,10 +66,6 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks
mCommandQueue = commandQueue;
mBlurUtils = blurUtils;
mCommandQueue.addCallback(this);
- mWalletPluginProvider = Dependency.get(ExtensionController.class)
- .newExtension(GlobalActionsPanelPlugin.class)
- .withPlugin(GlobalActionsPanelPlugin.class)
- .build();
}
@Override
@@ -89,8 +82,7 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks
if (mDisabled) return;
mGlobalActionsDialog = mGlobalActionsDialogLazy.get();
mGlobalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(),
- mDeviceProvisionedController.isDeviceProvisioned(),
- mWalletPluginProvider.get());
+ mDeviceProvisionedController.isDeviceProvisioned());
Dependency.get(KeyguardUpdateMonitor.class).requestFaceAuth();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 6d1109ee5f51..3544f60601a8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -17,14 +17,18 @@
package com.android.systemui.navigationbar;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -80,6 +84,8 @@ public class NavigationBarController implements Callbacks,
ConfigurationController.ConfigurationListener,
NavigationModeController.ModeChangedListener, Dumpable {
+ private static final float TABLET_MIN_DPS = 600;
+
private static final String TAG = NavigationBarController.class.getSimpleName();
private final Context mContext;
@@ -107,6 +113,8 @@ public class NavigationBarController implements Callbacks,
private final Handler mHandler;
private final DisplayManager mDisplayManager;
private final NavigationBarOverlayController mNavBarOverlayController;
+ private int mNavMode;
+ private boolean mIsTablet;
/** A displayId - nav bar maps. */
@VisibleForTesting
@@ -172,11 +180,30 @@ public class NavigationBarController implements Callbacks,
configurationController.addCallback(this);
mConfigChanges.applyNewConfig(mContext.getResources());
mNavBarOverlayController = navBarOverlayController;
+ mNavMode = mNavigationModeController.addListener(this);
mNavigationModeController.addListener(this);
}
@Override
public void onConfigChanged(Configuration newConfig) {
+ boolean isOldConfigTablet = mIsTablet;
+ mIsTablet = isTablet(newConfig);
+ boolean largeScreenChanged = mIsTablet != isOldConfigTablet;
+ // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded
+ if (isThreeButtonTaskbarFlagEnabled() &&
+ largeScreenChanged && mNavMode == NAV_BAR_MODE_3BUTTON) {
+ if (!mIsTablet) {
+ // Folded state, show 3 button nav bar
+ createNavigationBar(mContext.getDisplay(), null, null);
+ } else {
+ // Unfolded state, hide 3 button nav bars
+ for (int i = 0; i < mNavigationBars.size(); i++) {
+ removeNavigationBar(mNavigationBars.keyAt(i));
+ }
+ }
+ return;
+ }
+
if (mConfigChanges.applyNewConfig(mContext.getResources())) {
for (int i = 0; i < mNavigationBars.size(); i++) {
recreateNavigationBar(mNavigationBars.keyAt(i));
@@ -190,7 +217,19 @@ public class NavigationBarController implements Callbacks,
@Override
public void onNavigationModeChanged(int mode) {
+ final int oldMode = mNavMode;
+ mNavMode = mode;
mHandler.post(() -> {
+ // create/destroy nav bar based on nav mode only in unfolded state
+ if (isThreeButtonTaskbarFlagEnabled() && oldMode != mNavMode && mIsTablet) {
+ if (oldMode == NAV_BAR_MODE_3BUTTON &&
+ mNavigationBars.get(mContext.getDisplayId()) == null) {
+ // We remove navbar for 3 button unfolded, add it back in
+ createNavigationBar(mContext.getDisplay(), null, null);
+ } else if (mNavMode == NAV_BAR_MODE_3BUTTON) {
+ removeNavigationBar(mContext.getDisplayId());
+ }
+ }
for (int i = 0; i < mNavigationBars.size(); i++) {
NavigationBar navBar = mNavigationBars.valueAt(i);
if (navBar == null) {
@@ -212,6 +251,7 @@ public class NavigationBarController implements Callbacks,
@Override
public void onDisplayReady(int displayId) {
Display display = mDisplayManager.getDisplay(displayId);
+ mIsTablet = isTablet(mContext.getResources().getConfiguration());
createNavigationBar(display, null /* savedState */, null /* result */);
}
@@ -267,6 +307,10 @@ public class NavigationBarController implements Callbacks,
return;
}
+ if (isThreeButtonTaskbarEnabled()) {
+ return;
+ }
+
final int displayId = display.getDisplayId();
final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
@@ -398,6 +442,24 @@ public class NavigationBarController implements Callbacks,
return mNavigationBars.get(DEFAULT_DISPLAY);
}
+ private boolean isThreeButtonTaskbarEnabled() {
+ return mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON &&
+ isThreeButtonTaskbarFlagEnabled();
+ }
+
+ private boolean isThreeButtonTaskbarFlagEnabled() {
+ return SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
+ }
+
+ private boolean isTablet(Configuration newConfig) {
+ float density = Resources.getSystem().getDisplayMetrics().density;
+ int size = Math.min((int) (density * newConfig.screenWidthDp),
+ (int) (density* newConfig.screenHeightDp));
+ DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
+ float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+ return (size / densityRatio) >= TABLET_MIN_DPS;
+ }
+
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
for (int i = 0; i < mNavigationBars.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 2ca6a92ecc80..01c80f6d33fe 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -281,7 +281,7 @@ public class NavigationBarView extends FrameLayout implements
// When in gestural and the IME is showing, don't use the nearest region since it will take
// gesture space away from the IME
info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- info.touchableRegion.set(getButtonLocations(false /* includeFloatingRotationButton */,
+ info.touchableRegion.set(getButtonLocations(false /* includeFloatingButtons */,
false /* inScreen */, false /* useNearestRegion */));
};
@@ -982,7 +982,7 @@ public class NavigationBarView extends FrameLayout implements
*/
public void notifyActiveTouchRegions() {
mOverviewProxyService.onActiveNavBarRegionChanges(
- getButtonLocations(true /* includeFloatingRotationButton */, true /* inScreen */,
+ getButtonLocations(true /* includeFloatingButtons */, true /* inScreen */,
true /* useNearestRegion */));
}
@@ -995,14 +995,14 @@ public class NavigationBarView extends FrameLayout implements
}
/**
- * @param includeFloatingRotationButton Whether to include the floating rotation button in the
- * region for all the buttons
+ * @param includeFloatingButtons Whether to include the floating rotation and overlay button in
+ * the region for all the buttons
* @param inScreenSpace Whether to return values in screen space or window space
* @param useNearestRegion Whether to use the nearest region instead of the actual button bounds
* @return
*/
- private Region getButtonLocations(boolean includeFloatingRotationButton,
- boolean inScreenSpace, boolean useNearestRegion) {
+ private Region getButtonLocations(boolean includeFloatingButtons, boolean inScreenSpace,
+ boolean useNearestRegion) {
if (useNearestRegion && !inScreenSpace) {
// We currently don't support getting the nearest region in anything but screen space
useNearestRegion = false;
@@ -1014,13 +1014,13 @@ public class NavigationBarView extends FrameLayout implements
updateButtonLocation(getRecentsButton(), inScreenSpace, useNearestRegion);
updateButtonLocation(getImeSwitchButton(), inScreenSpace, useNearestRegion);
updateButtonLocation(getAccessibilityButton(), inScreenSpace, useNearestRegion);
- if (includeFloatingRotationButton && mFloatingRotationButton.isVisible()) {
+ if (includeFloatingButtons && mFloatingRotationButton.isVisible()) {
// Note: this button is floating so the nearest region doesn't apply
updateButtonLocation(mFloatingRotationButton.getCurrentView(), inScreenSpace);
} else {
updateButtonLocation(getRotateSuggestionButton(), inScreenSpace, useNearestRegion);
}
- if (mNavBarOverlayController.isNavigationBarOverlayEnabled()
+ if (includeFloatingButtons && mNavBarOverlayController.isNavigationBarOverlayEnabled()
&& mNavBarOverlayController.isVisible()) {
// Note: this button is floating so the nearest region doesn't apply
updateButtonLocation(mNavBarOverlayController.getCurrentView(), inScreenSpace);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index afbb197c4a12..6d23739b9c78 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -24,7 +24,6 @@ import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -62,7 +61,6 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
import android.view.InputDevice;
-import android.view.InputMonitor;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -89,7 +87,6 @@ import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -358,24 +355,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
@Override
- public Bundle monitorGestureInput(String name, int displayId) {
- if (!verifyCaller("monitorGestureInput")) {
- return null;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- final InputMonitor monitor =
- InputManager.getInstance().monitorGestureInput(name, displayId);
- final Bundle result = new Bundle();
- result.putParcelable(KEY_EXTRA_INPUT_MONITOR,
- InputMonitorCompat.obtainReturnValue(monitor));
- return result;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
public void notifyAccessibilityButtonClicked(int displayId) {
if (!verifyCaller("notifyAccessibilityButtonClicked")) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index fd060e6d486d..718a85a98877 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -58,6 +58,7 @@ class WiredChargingRippleController @Inject constructor(
title = "Wired Charging Animation"
flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+ setTrustedOverlay()
}
@VisibleForTesting
@@ -103,7 +104,10 @@ class WiredChargingRippleController @Inject constructor(
}
fun startRipple() {
- if (rippleView.rippleInProgress) {
+ if (rippleView.rippleInProgress || rippleView.parent != null) {
+ // Skip if ripple is still playing, or not playing but already added the parent
+ // (which might happen just before the animation starts or right after
+ // the animation ends.)
return
}
val mWM = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 8fae7200b56f..500838fac5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -71,7 +71,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
-import com.android.internal.widget.MessagingLayout;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -658,10 +657,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
boolean beforeS = mEntry.targetSdk < Build.VERSION_CODES.S;
int smallHeight;
- View expandedView = layout.getExpandedChild();
- boolean isMediaLayout = expandedView != null
- && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
- boolean isMessagingLayout = contractedView instanceof MessagingLayout;
boolean isCallLayout = contractedView instanceof CallLayout;
if (customView && beforeS && !mIsSummaryWithChildren) {
@@ -672,12 +667,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else {
smallHeight = mMaxSmallHeightBeforeS;
}
- } else if (isMessagingLayout) {
- // TODO(b/173204301): MessagingStyle notifications currently look broken when we enforce
- // the standard notification height, so we have to afford them more vertical space to
- // make sure we don't crop them terribly. We actually need to revisit this and give
- // them a headerless design, then remove this hack.
- smallHeight = mMaxSmallHeightLarge;
} else if (isCallLayout) {
smallHeight = mMaxExpandedHeight;
} else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 383bb7e41a91..08981f1215f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -23,12 +23,9 @@ import com.android.internal.widget.CachingIconView
import com.android.internal.widget.ConversationLayout
import com.android.internal.widget.MessagingLinearLayout
import com.android.systemui.R
-import com.android.systemui.statusbar.TransformableView
-import com.android.systemui.statusbar.ViewTransformationHelper
import com.android.systemui.statusbar.notification.NotificationUtils
-import com.android.systemui.statusbar.notification.TransformState
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.notification.row.HybridNotificationView
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationMessagingTemplateViewWrapper.setCustomImageMessageTransform
/**
* Wraps a notification containing a conversation template
@@ -93,33 +90,7 @@ class NotificationConversationTemplateViewWrapper constructor(
appName,
conversationTitleView)
- // Let's ignore the image message container since that is transforming as part of the
- // messages already
- mTransformationHelper.setCustomTransformation(
- object : ViewTransformationHelper.CustomTransformation() {
- override fun transformTo(
- ownState: TransformState,
- otherView: TransformableView,
- transformationAmount: Float
- ): Boolean {
- if (otherView is HybridNotificationView) {
- return false
- }
- // we're hidden by default by the transformState
- ownState.ensureVisible()
- // Let's do nothing otherwise, this is already handled by the messages
- return true
- }
-
- override fun transformFrom(
- ownState: TransformState,
- otherView: TransformableView,
- transformationAmount: Float
- ): Boolean =
- transformTo(ownState, otherView, transformationAmount)
- },
- imageMessageContainer.id
- )
+ setCustomImageMessageTransform(mTransformationHelper, imageMessageContainer)
addViewsTransformingToSimilar(
conversationIconView,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
index c9a274294d16..c587ce05b13f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
@@ -18,12 +18,17 @@ package com.android.systemui.statusbar.notification.row.wrapper;
import android.content.Context;
import android.view.View;
+import android.view.ViewGroup;
import com.android.internal.widget.MessagingLayout;
import com.android.internal.widget.MessagingLinearLayout;
import com.android.systemui.R;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.TransformState;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.HybridNotificationView;
/**
* Wraps a notification containing a messaging template
@@ -31,12 +36,17 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
private final int mMinHeightWithActions;
+ private final View mTitle;
+ private final View mTitleInHeader;
private MessagingLayout mMessagingLayout;
private MessagingLinearLayout mMessagingLinearLayout;
+ private ViewGroup mImageMessageContainer;
protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
+ mTitle = mView.findViewById(com.android.internal.R.id.title);
+ mTitleInHeader = mView.findViewById(com.android.internal.R.id.header_text_secondary);
mMessagingLayout = (MessagingLayout) view;
mMinHeightWithActions = NotificationUtils.getFontScaledHeight(ctx,
R.dimen.notification_messaging_actions_min_height);
@@ -44,6 +54,7 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
private void resolveViews() {
mMessagingLinearLayout = mMessagingLayout.getMessagingLinearLayout();
+ mImageMessageContainer = mMessagingLayout.getImageMessageContainer();
}
@Override
@@ -59,8 +70,48 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
// This also clears the existing types
super.updateTransformedTypes();
if (mMessagingLinearLayout != null) {
- mTransformationHelper.addTransformedView(mMessagingLinearLayout.getId(),
- mMessagingLinearLayout);
+ mTransformationHelper.addTransformedView(mMessagingLinearLayout);
+ }
+ // The title is not as important for messaging, and stays in the header when expanded,
+ // but this ensures it animates cleanly between the two positions
+ if (mTitle == null && mTitleInHeader != null) {
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
+ mTitleInHeader);
+ }
+ setCustomImageMessageTransform(mTransformationHelper, mImageMessageContainer);
+ }
+
+ static void setCustomImageMessageTransform(
+ ViewTransformationHelper transformationHelper, ViewGroup imageMessageContainer) {
+ if (imageMessageContainer != null) {
+ // Let's ignore the image message container since that is transforming as part of the
+ // messages already. This is also required to prevent a clipping artifact caused by the
+ // alpha layering triggering hardware rendering mode that in turn results in more
+ // aggressive clipping than we want.
+ transformationHelper.setCustomTransformation(
+ new ViewTransformationHelper.CustomTransformation() {
+ @Override
+ public boolean transformTo(
+ TransformState ownState,
+ TransformableView otherView,
+ float transformationAmount) {
+ if (otherView instanceof HybridNotificationView) {
+ return false;
+ }
+ // we're hidden by default by the transformState
+ ownState.ensureVisible();
+ // Let's do nothing otherwise, this is already handled by the messages
+ return true;
+ }
+
+ @Override
+ public boolean transformFrom(
+ TransformState ownState,
+ TransformableView otherView,
+ float transformationAmount) {
+ return transformTo(ownState, otherView, transformationAmount);
+ }
+ }, imageMessageContainer.getId());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index e0b58125aabd..48f34b3b7716 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -56,6 +56,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
private ProgressBar mProgressBar;
private TextView mTitle;
private TextView mText;
+ protected View mSmartReplyContainer;
protected View mActionsContainer;
private int mContentHeight;
@@ -160,6 +161,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
// It's still a viewstub
mProgressBar = null;
}
+ mSmartReplyContainer = mView.findViewById(com.android.internal.R.id.smart_reply_container);
mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
mActions = mView.findViewById(com.android.internal.R.id.actions);
mRemoteInputHistory = mView.findViewById(
@@ -275,6 +277,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
mProgressBar);
}
addViewsTransformingToSimilar(mLeftIcon);
+ addTransformedViews(mSmartReplyContainer);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 707135c3d95b..30d9841e41ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -16,11 +16,13 @@
package com.android.systemui.statusbar.phone
+import android.annotation.IntDef
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.biometrics.BiometricSourceType
import android.provider.Settings
import com.android.systemui.Dumpable
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -37,9 +39,18 @@ open class KeyguardBypassController : Dumpable {
private val mKeyguardStateController: KeyguardStateController
private val statusBarStateController: StatusBarStateController
+ @BypassOverride private val bypassOverride: Int
private var hasFaceFeature: Boolean
private var pendingUnlock: PendingUnlock? = null
+ @IntDef(
+ FACE_UNLOCK_BYPASS_NO_OVERRIDE,
+ FACE_UNLOCK_BYPASS_ALWAYS,
+ FACE_UNLOCK_BYPASS_NEVER
+ )
+ @Retention(AnnotationRetention.SOURCE)
+ private annotation class BypassOverride
+
/**
* Pending unlock info:
*
@@ -60,7 +71,14 @@ open class KeyguardBypassController : Dumpable {
* If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
*/
var bypassEnabled: Boolean = false
- get() = field && mKeyguardStateController.isFaceAuthEnabled
+ get() {
+ val enabled = when (bypassOverride) {
+ FACE_UNLOCK_BYPASS_ALWAYS -> true
+ FACE_UNLOCK_BYPASS_NEVER -> false
+ else -> field
+ }
+ return enabled && mKeyguardStateController.isFaceAuthEnabled
+ }
private set
var bouncerShowing: Boolean = false
@@ -86,6 +104,8 @@ open class KeyguardBypassController : Dumpable {
this.mKeyguardStateController = keyguardStateController
this.statusBarStateController = statusBarStateController
+ bypassOverride = context.resources.getInteger(R.integer.config_face_unlock_bypass_override)
+
hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)
if (!hasFaceFeature) {
return
@@ -198,5 +218,9 @@ open class KeyguardBypassController : Dumpable {
companion object {
const val BYPASS_PANEL_FADE_DURATION = 67
+
+ private const val FACE_UNLOCK_BYPASS_NO_OVERRIDE = 0
+ private const val FACE_UNLOCK_BYPASS_ALWAYS = 1
+ private const val FACE_UNLOCK_BYPASS_NEVER = 2
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 55b80dd69b6a..db7736620c26 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -633,7 +633,7 @@ public class BubblesManager implements Dumpable {
} else {
mNotificationGroupManager.onEntryRemoved(entry);
}
- });
+ }, mSysuiMainExecutor);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 9017dd244fb4..a8709150c3e4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -20,6 +20,7 @@ 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.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -31,6 +32,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.util.AttributeSet;
import android.view.View;
+import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.android.internal.colorextraction.ColorExtractor;
@@ -48,6 +50,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
@@ -98,9 +101,14 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Mock
private AnimatableClockView mLargeClockView;
@Mock
+ private FrameLayout mLargeClockFrame;
+ @Mock
BatteryController mBatteryController;
+ @Mock
+ ConfigurationController mConfigurationController;
private KeyguardClockSwitchController mController;
+ private View mStatusArea;
@Before
public void setup() {
@@ -108,10 +116,13 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
when(mView.findViewById(R.id.left_aligned_notification_icon_container))
.thenReturn(mNotificationIcons);
+ when(mNotificationIcons.getLayoutParams()).thenReturn(
+ mock(RelativeLayout.LayoutParams.class));
when(mView.getContext()).thenReturn(getContext());
when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
+ when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
when(mClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext());
@@ -131,10 +142,15 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
mPluginManager,
mFeatureFlags,
mExecutor,
- mBatteryController);
+ mBatteryController,
+ mConfigurationController);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
+
+ mStatusArea = mock(View.class);
+ when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
+
}
@Test
@@ -197,39 +213,40 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
public void testSmartspacePluginConnectedRemovesKeyguardStatusArea() {
mController.init();
- View statusArea = mock(View.class);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
-
- View nic = mock(View.class);
- when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
- when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
-
BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
TestView view = mock(TestView.class);
when(plugin.getView(any())).thenReturn(view);
mController.mPluginListener.onPluginConnected(plugin, mContext);
- verify(statusArea).setVisibility(View.GONE);
+ verify(mStatusArea).setVisibility(View.GONE);
}
@Test
public void testSmartspacePluginDisconnectedShowsKeyguardStatusArea() {
mController.init();
- View statusArea = mock(View.class);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
+ BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
+ TestView view = mock(TestView.class);
+ when(plugin.getView(any())).thenReturn(view);
+
+ mController.mPluginListener.onPluginConnected(plugin, mContext);
+ mController.mPluginListener.onPluginDisconnected(plugin);
+ verify(mStatusArea).setVisibility(View.VISIBLE);
+ }
- View nic = mock(View.class);
- when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
- when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
+ @Test
+ public void testThemeChangeNotifiesSmartspace() {
+ mController.init();
BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
TestView view = mock(TestView.class);
when(plugin.getView(any())).thenReturn(view);
mController.mPluginListener.onPluginConnected(plugin, mContext);
- mController.mPluginListener.onPluginDisconnected(plugin);
- verify(statusArea).setVisibility(View.VISIBLE);
+
+ reset(view);
+ mController.getConfigurationListener().onThemeChanged();
+ verify(view).setPrimaryTextColor(anyInt());
}
private void verifyAttachment(VerificationMode times) {
@@ -246,5 +263,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
}
public void registerDataProvider(BcSmartspaceDataPlugin plugin) { }
+
+ public void setPrimaryTextColor(int color) { }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index d544f7378f8a..42cc1fa99909 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -49,7 +49,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.face.FaceManager;
@@ -188,8 +187,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
doAnswer(invocation -> {
IBiometricEnabledOnKeyguardCallback callback = invocation.getArgument(0);
- callback.onChanged(BiometricSourceType.FACE, true /* enabled */,
- KeyguardUpdateMonitor.getCurrentUser());
+ callback.onChanged(true /* enabled */, KeyguardUpdateMonitor.getCurrentUser());
return null;
}).when(mBiometricManager).registerEnabledOnKeyguardCallback(any());
when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -495,6 +493,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
}
private void testFingerprintWhenStrongAuth(int strongAuth) {
+ // Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
+ // will trigger updateBiometricListeningState();
+ clearInvocations(mFingerprintManager);
+ mKeyguardUpdateMonitor.resetBiometricListeningState();
+
when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
@@ -537,7 +540,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
authCallback.onAuthenticationFailed();
// THEN aod interrupt is cancelled
- verify(mAuthController).onCancelAodInterrupt();
+ verify(mAuthController).onCancelUdfps();
}
@Test
@@ -557,7 +560,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
authCallback.onAuthenticationError(0, "");
// THEN aod interrupt is cancelled
- verify(mAuthController).onCancelAodInterrupt();
+ verify(mAuthController).onCancelUdfps();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index bbd3ce89b997..0aa182fb1e81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -259,7 +259,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
// WHEN it is cancelled
- mUdfpsController.onCancelAodInterrupt();
+ mUdfpsController.onCancelUdfps();
// THEN the illumination is hidden
verify(mUdfpsView).stopIllumination();
}
diff --git a/services/Android.bp b/services/Android.bp
index ad1406c73c2f..20b89de7f2a6 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -65,6 +65,7 @@ filegroup {
":services.texttospeech-sources",
":services.usage-sources",
":services.usb-sources",
+ ":services.uwb-sources",
":services.voiceinteraction-sources",
":services.wifi-sources",
],
@@ -129,6 +130,7 @@ java_library {
"services.texttospeech",
"services.usage",
"services.usb",
+ "services.uwb",
"services.voiceinteraction",
"services.wifi",
"service-blobstore",
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a230f808ee9e..f8b770b4ec84 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -456,6 +456,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
} : null;
}
+ void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
+ mPendingFillRequest = null;
+ mWaitForInlineRequest = inlineRequest != null;
+ mPendingInlineSuggestionsRequest = inlineRequest;
+ }
+
void maybeRequestFillLocked() {
if (mPendingFillRequest == null) {
return;
@@ -886,6 +892,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
// Now request the assist structure data.
+ requestAssistStructureLocked(requestId, flags);
+ }
+
+ @GuardedBy("mLock")
+ private void requestAssistStructureLocked(int requestId, int flags) {
try {
final Bundle receiverExtras = new Bundle();
receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
@@ -1052,12 +1063,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (requestLog != null) {
requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
}
- processNullResponseLocked(requestId, requestFlags);
+ processNullResponseOrFallbackLocked(requestId, requestFlags);
return;
}
fieldClassificationIds = response.getFieldClassificationIds();
- if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
+ if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
+ && !mService.isFieldClassificationEnabledLocked()) {
Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
processNullResponseLocked(requestId, requestFlags);
return;
@@ -1136,6 +1148,26 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
+ @GuardedBy("mLock")
+ private void processNullResponseOrFallbackLocked(int requestId, int flags) {
+ if (!mSessionFlags.mClientSuggestionsEnabled) {
+ processNullResponseLocked(requestId, flags);
+ return;
+ }
+
+ // fallback to the default platform password manager
+ mSessionFlags.mClientSuggestionsEnabled = false;
+
+ final InlineSuggestionsRequest inlineRequest =
+ (mLastInlineSuggestionsRequest != null
+ && mLastInlineSuggestionsRequest.first == requestId)
+ ? mLastInlineSuggestionsRequest.second : null;
+ mAssistReceiver.newAutofillRequestLocked(inlineRequest);
+ requestAssistStructureLocked(requestId,
+ flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
+ return;
+ }
+
// FillServiceCallbacks
@Override
public void onFillRequestFailure(int requestId, @Nullable CharSequence message) {
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index c49b8e8e77c6..78610a2857bd 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -138,6 +138,8 @@ public class BinderCallsStatsService extends Binder {
private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data";
private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY =
"latency_observer_sampling_interval";
+ private static final String SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY =
+ "latency_observer_push_interval_minutes";
private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY =
"latency_histogram_bucket_count";
private static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY =
@@ -218,7 +220,9 @@ public class BinderCallsStatsService extends Binder {
mParser.getFloat(
SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY,
BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT));
-
+ binderLatencyObserver.setPushInterval(mParser.getInt(
+ SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY,
+ BinderLatencyObserver.STATSD_PUSH_INTERVAL_MINUTES_DEFAULT));
final boolean enabled =
mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d9cc4b41f797..4d96162149e2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1353,8 +1353,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
new NetworkInfo(TYPE_NONE, 0, "", ""),
new LinkProperties(), new NetworkCapabilities(),
new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
- new NetworkAgentConfig(), this, null, null, 0, INVALID_UID, mQosCallbackTracker,
- mDeps);
+ new NetworkAgentConfig(), this, null, null, 0, INVALID_UID,
+ mLingerDelayMs, mQosCallbackTracker, mDeps);
}
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -3167,6 +3167,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
}
+ break;
+ }
+ case NetworkAgent.EVENT_LINGER_DURATION_CHANGED: {
+ nai.setLingerDuration((int) arg.second);
+ break;
}
}
}
@@ -6516,7 +6521,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker, mDeps);
+ this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,
+ mQosCallbackTracker, mDeps);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
processCapabilitiesFromAgent(nai, nc);
@@ -7759,7 +7765,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
log(" accepting network in place of " + previousSatisfier.toShortString());
}
previousSatisfier.removeRequest(previousRequest.requestId);
- previousSatisfier.lingerRequest(previousRequest.requestId, now, mLingerDelayMs);
+ previousSatisfier.lingerRequest(previousRequest.requestId, now);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 611fe7ad8c78..98bfa28d6415 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -376,7 +376,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private final LocalLog mListenLog = new LocalLog(200);
- private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
+ private List<List<PhysicalChannelConfig>> mPhysicalChannelConfigs;
private boolean[] mIsDataEnabled;
@@ -716,7 +716,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mTelephonyDisplayInfos[i] = null;
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
- mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+ mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
mLinkCapacityEstimateLists.add(i, new ArrayList<>());
@@ -816,7 +816,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mTelephonyDisplayInfos[i] = null;
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
- mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+ mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
mLinkCapacityEstimateLists.add(i, new ArrayList<>());
@@ -1314,8 +1314,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
r.callback.onPhysicalChannelConfigChanged(
shouldSanitizeLocationForPhysicalChannelConfig(r)
- ? getLocationSanitizedConfigs(mPhysicalChannelConfigs)
- : mPhysicalChannelConfigs);
+ ? getLocationSanitizedConfigs(
+ mPhysicalChannelConfigs.get(phoneId))
+ : mPhysicalChannelConfigs.get(phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -2568,7 +2569,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
- mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId));
+ mPhysicalChannelConfigs.set(phoneId, configs);
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
@@ -2775,6 +2776,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mDataEnabledReason=" + mDataEnabledReason);
pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]);
pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]);
+ pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i));
pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i));
pw.decreaseIndent();
}
@@ -2785,7 +2787,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.println("mDefaultPhoneId=" + mDefaultPhoneId);
pw.println("mDefaultSubId=" + mDefaultSubId);
- pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs);
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 3b31ab272ff2..039f4d9f3cce 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -362,8 +362,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
/** Notifies the VcnManagementService that external dependencies can be set up. */
public void systemReady() {
- mContext.getSystemService(ConnectivityManager.class)
- .registerNetworkProvider(mNetworkProvider);
+ mNetworkProvider.register();
mContext.getSystemService(ConnectivityManager.class)
.registerNetworkCallback(
new NetworkRequest.Builder().clearCapabilities().build(),
@@ -935,13 +934,31 @@ public class VcnManagementService extends IVcnManagementService.Stub {
pw.println("VcnManagementService dump:");
pw.increaseIndent();
+ pw.println("mNetworkProvider:");
+ pw.increaseIndent();
mNetworkProvider.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
+
+ pw.println("mTrackingNetworkCallback:");
+ pw.increaseIndent();
+ mTrackingNetworkCallback.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
synchronized (mLock) {
+ pw.println("mLastSnapshot:");
+ pw.increaseIndent();
+ mLastSnapshot.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
+
pw.println("mVcns:");
+ pw.increaseIndent();
for (Vcn vcn : mVcns.values()) {
vcn.dump(pw);
}
+ pw.decreaseIndent();
pw.println();
}
@@ -1003,6 +1020,24 @@ public class VcnManagementService extends IVcnManagementService.Stub {
return false;
}
+
+ /** Dumps the state of this snapshot for logging and debugging purposes. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("TrackingNetworkCallback:");
+ pw.increaseIndent();
+
+ pw.println("mCaps:");
+ pw.increaseIndent();
+ synchronized (mCaps) {
+ for (Entry<Network, NetworkCapabilities> entry : mCaps.entrySet()) {
+ pw.println(entry.getKey() + ": " + entry.getValue());
+ }
+ }
+ pw.decreaseIndent();
+ pw.println();
+
+ pw.decreaseIndent();
+ }
}
/** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2a1a8971ec8c..e3b06d696423 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2500,7 +2500,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
- broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
+ broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null, null,
OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
@@ -3940,7 +3940,7 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.getUserId(uid));
}
@@ -7531,7 +7531,7 @@ public class ActivityManagerService extends IActivityManager.Stub
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
@@ -7543,8 +7543,8 @@ public class ActivityManagerService extends IActivityManager.Stub
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) {}
- }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, OP_NONE, null,
- true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
UserHandle.USER_ALL);
} catch (Throwable e) {
Slog.wtf(TAG, "Failed sending first user broadcasts", e);
@@ -12302,7 +12302,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, null, -1, -1, false, null, null, OP_NONE, null, receivers,
+ null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
@@ -12544,13 +12544,13 @@ public class ActivityManagerService extends IActivityManager.Stub
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
- int realCallingPid, int userId) {
+ Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions,
+ int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid,
+ int callingUid, int realCallingUid, int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
- appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
- realCallingPid, userId, false /* allowBackgroundActivityStarts */,
+ excludedPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid,
+ realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */,
null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}
@@ -12558,9 +12558,11 @@ public class ActivityManagerService extends IActivityManager.Stub
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
- int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
+ Bundle resultExtras, String[] requiredPermissions,
+ String[] excludedPermissions, int appOp, Bundle bOptions,
+ boolean ordered, boolean sticky, int callingPid, int callingUid,
+ int realCallingUid, int realCallingPid, int userId,
+ boolean allowBackgroundActivityStarts,
@Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastAllowList) {
intent = new Intent(intent);
@@ -13139,8 +13141,8 @@ public class ActivityManagerService extends IActivityManager.Stub
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
- resultCode, resultData, resultExtras, ordered, sticky, false, userId,
+ requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
+ resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, backgroundActivityStartsToken,
timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
@@ -13237,10 +13239,10 @@ public class ActivityManagerService extends IActivityManager.Stub
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
- resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts, backgroundActivityStartsToken,
- timeoutExempt);
+ requiredPermissions, excludedPermissions, appOp, brOptions,
+ receivers, resultTo, resultCode, resultData, resultExtras,
+ ordered, sticky, false, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
@@ -13366,14 +13368,14 @@ public class ActivityManagerService extends IActivityManager.Stub
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
return broadcastIntentWithFeature(caller, null, intent, resolvedType, resultTo, resultCode,
- resultData, resultExtras, requiredPermissions, appOp, bOptions, serialized, sticky,
- userId);
+ resultData, resultExtras, requiredPermissions, null, appOp, bOptions, serialized,
+ sticky, userId);
}
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
- String[] requiredPermissions, int appOp, Bundle bOptions,
+ String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
@@ -13388,8 +13390,8 @@ public class ActivityManagerService extends IActivityManager.Stub
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, appOp, bOptions, serialized, sticky,
- callingPid, callingUid, callingUid, callingPid, userId);
+ requiredPermissions, excludedPermissions, appOp, bOptions, serialized,
+ sticky, callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -13410,7 +13412,7 @@ public class ActivityManagerService extends IActivityManager.Stub
: new String[] {requiredPermission};
try {
return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
- resultTo, resultCode, resultData, resultExtras, requiredPermissions,
+ resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken,
@@ -15615,7 +15617,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/,
null /*callerPackage*/, null /*callingFeatureId*/, intent,
null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/,
- null /*resultExtras*/, requiredPermissions, AppOpsManager.OP_NONE,
+ null /*resultExtras*/, requiredPermissions, null, AppOpsManager.OP_NONE,
bOptions /*options*/, serialized, false /*sticky*/, callingPid,
callingUid, callingUid, callingPid, userId,
false /*allowBackgroundStarts*/,
@@ -15740,8 +15742,8 @@ public class ActivityManagerService extends IActivityManager.Stub
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.USER_ALL);
+ null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
@@ -15751,8 +15753,9 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.USER_ALL);
+ null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.USER_ALL);
}
// Send a broadcast to PackageInstallers if the configuration change is interesting
@@ -15766,7 +15769,7 @@ public class ActivityManagerService extends IActivityManager.Stub
String[] permissions =
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null,
- permissions, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ permissions, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -15791,7 +15794,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 42aac295c027..6fa8ecd41d7c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -760,7 +760,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.flush();
Bundle bundle = mBroadcastOptions == null ? null : mBroadcastOptions.toBundle();
mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, bundle, true, false,
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE, bundle, true, false,
mUserId);
if (!mAsync) {
receiver.waitForFinish();
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 60e8d54676ec..4942b110cf3c 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -205,7 +205,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
mPowerStatsInternal = psi;
boolean[] supportedStdBuckets = null;
- int numCustomBuckets = 0;
+ String[] customBucketNames = null;
if (mPowerStatsInternal != null) {
final SparseArray<EnergyConsumer> idToConsumer
= populateEnergyConsumerSubsystemMapsLocked();
@@ -227,12 +227,12 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
+ e.getCause());
// Continue running, later attempts to query may be successful.
}
- numCustomBuckets = mMeasuredEnergySnapshot.getNumOtherOrdinals();
+ customBucketNames = mMeasuredEnergySnapshot.getOtherOrdinalNames();
supportedStdBuckets = getSupportedEnergyBuckets(idToConsumer);
}
}
synchronized (mStats) {
- mStats.initMeasuredEnergyStatsLocked(supportedStdBuckets, numCustomBuckets);
+ mStats.initMeasuredEnergyStatsLocked(supportedStdBuckets, customBucketNames);
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a5474d0b8c72..f0b116cc1869 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1419,6 +1419,7 @@ public final class BroadcastQueue {
skip = true;
}
}
+
boolean isSingleton = false;
try {
isSingleton = mService.isSingleton(info.activityInfo.processName,
@@ -1553,6 +1554,37 @@ public final class BroadcastQueue {
+ info.activityInfo.applicationInfo.uid + " : user is not running");
}
+ if (!skip && r.excludedPermissions != null && r.excludedPermissions.length > 0) {
+ for (int i = 0; i < r.excludedPermissions.length; i++) {
+ String excludedPermission = r.excludedPermissions[i];
+ try {
+ perm = AppGlobals.getPackageManager()
+ .checkPermission(excludedPermission,
+ info.activityInfo.applicationInfo.packageName,
+ UserHandle
+ .getUserId(info.activityInfo.applicationInfo.uid));
+ } catch (RemoteException e) {
+ perm = PackageManager.PERMISSION_DENIED;
+ }
+
+ if (perm == PackageManager.PERMISSION_GRANTED) {
+ skip = true;
+ break;
+ }
+
+ int appOp = AppOpsManager.permissionToOpCode(excludedPermission);
+ if (appOp != AppOpsManager.OP_NONE) {
+ if (mService.getAppOpsManager().checkOpNoThrow(appOp,
+ info.activityInfo.applicationInfo.uid,
+ info.activityInfo.packageName)
+ == AppOpsManager.MODE_ALLOWED) {
+ skip = true;
+ break;
+ }
+ }
+ }
+ }
+
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 198ba34e3956..801559620457 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -62,6 +62,7 @@ final class BroadcastRecord extends Binder {
final int userId; // user id this broadcast was for
final String resolvedType; // the resolved data type
final String[] requiredPermissions; // permissions the caller has required
+ final String[] excludedPermissions; // permissions to exclude
final int appOp; // an app op that is associated with this broadcast
final BroadcastOptions options; // BroadcastOptions supplied by caller
final List receivers; // contains BroadcastFilter and ResolveInfo
@@ -142,6 +143,10 @@ final class BroadcastRecord extends Binder {
pw.print(Arrays.toString(requiredPermissions));
pw.print(" appOp="); pw.println(appOp);
}
+ if (excludedPermissions != null && excludedPermissions.length > 0) {
+ pw.print(prefix); pw.print("excludedPermissions=");
+ pw.print(Arrays.toString(excludedPermissions));
+ }
if (options != null) {
pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
}
@@ -240,11 +245,11 @@ final class BroadcastRecord extends Binder {
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
@Nullable String _callerFeatureId, int _callingPid, int _callingUid,
boolean _callerInstantApp, String _resolvedType,
- String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
- IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
- boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
- boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken,
- boolean timeoutExempt) {
+ String[] _requiredPermissions, String[] _excludedPermissions, int _appOp,
+ BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
+ String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
+ boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken, boolean timeoutExempt) {
if (_intent == null) {
throw new NullPointerException("Can't construct with a null intent");
}
@@ -259,6 +264,7 @@ final class BroadcastRecord extends Binder {
callerInstantApp = _callerInstantApp;
resolvedType = _resolvedType;
requiredPermissions = _requiredPermissions;
+ excludedPermissions = _excludedPermissions;
appOp = _appOp;
options = _options;
receivers = _receivers;
@@ -299,6 +305,7 @@ final class BroadcastRecord extends Binder {
userId = from.userId;
resolvedType = from.resolvedType;
requiredPermissions = from.requiredPermissions;
+ excludedPermissions = from.excludedPermissions;
appOp = from.appOp;
options = from.options;
receivers = from.receivers;
@@ -356,8 +363,8 @@ final class BroadcastRecord extends Binder {
// build a new BroadcastRecord around that single-target list
BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, appOp, options, splitReceivers, resultTo, resultCode,
- resultData, resultExtras, ordered, sticky, initialSticky, userId,
+ requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
+ resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
split.splitToken = this.splitToken;
diff --git a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
index f9296a0e64fc..65d47550a2ed 100644
--- a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
+++ b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
@@ -99,14 +99,6 @@ public class MeasuredEnergySnapshot {
mAttributionSnapshots = new SparseArray<>(mNumOtherOrdinals);
}
- /**
- * Returns the number of ordinals for {@link EnergyConsumerType#OTHER}, i.e. the number of
- * custom energy buckets supported by the device.
- */
- public int getNumOtherOrdinals() {
- return mNumOtherOrdinals;
- }
-
/** Class for returning the relevant data calculated from the measured energy delta */
static class MeasuredEnergyDeltaData {
/** The chargeUC for {@link EnergyConsumerType#BLUETOOTH}. */
@@ -147,7 +139,7 @@ public class MeasuredEnergySnapshot {
* Fields with no interesting data (consumers not present in ecrs or with no energy
* difference) will generally be left as their default values.
* otherTotalChargeUC and otherUidChargesUC are always either both null or both of
- * length {@link #getNumOtherOrdinals()}.
+ * length {@link #getOtherOrdinalNames().length}.
* Returns null, if ecrs is null or empty.
*/
public @Nullable MeasuredEnergyDeltaData updateAndGetDelta(EnergyConsumerResult[] ecrs,
@@ -237,8 +229,8 @@ public class MeasuredEnergySnapshot {
case EnergyConsumerType.OTHER:
if (output.otherTotalChargeUC == null) {
- output.otherTotalChargeUC = new long[getNumOtherOrdinals()];
- output.otherUidChargesUC = new SparseLongArray[getNumOtherOrdinals()];
+ output.otherTotalChargeUC = new long[mNumOtherOrdinals];
+ output.otherUidChargesUC = new SparseLongArray[mNumOtherOrdinals];
}
output.otherTotalChargeUC[ordinal] = deltaChargeUC;
output.otherUidChargesUC[ordinal] = otherUidCharges;
@@ -342,6 +334,23 @@ public class MeasuredEnergySnapshot {
pw.println();
}
+ /**
+ * Returns the names of ordinals for {@link EnergyConsumerType#OTHER}, i.e. the names of
+ * custom energy buckets supported by the device.
+ */
+ public String[] getOtherOrdinalNames() {
+ final String[] names = new String[mNumOtherOrdinals];
+ int consumerIndex = 0;
+ final int size = mEnergyConsumers.size();
+ for (int idx = 0; idx < size; idx++) {
+ final EnergyConsumer consumer = mEnergyConsumers.valueAt(idx);
+ if (consumer.type == (int) EnergyConsumerType.OTHER) {
+ names[consumerIndex++] = consumer.name;
+ }
+ }
+ return names;
+ }
+
/** Determines the number of ordinals for a given {@link EnergyConsumerType}. */
private static int calculateNumOrdinals(@EnergyConsumerType int type,
SparseArray<EnergyConsumer> idToConsumer) {
@@ -361,5 +370,4 @@ public class MeasuredEnergySnapshot {
// since the last snapshot. Round off to the nearest whole long.
return (deltaEnergyUJ * MILLIVOLTS_PER_VOLT + (avgVoltageMV / 2)) / avgVoltageMV;
}
-
}
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 984fe409b086..756209824614 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -124,7 +124,7 @@ public abstract class PreBootBroadcaster extends IIntentReceiver.Stub {
REASON_PRE_BOOT_COMPLETED, "");
synchronized (mService) {
mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
- null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
+ null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a5d0e72a81ae..ba3e1fb95e7d 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2936,8 +2936,8 @@ class UserController implements Handler.Callback {
// TODO b/64165549 Verify that mLock is not held before calling AMS methods
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
- resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp,
- bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
+ resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
+ appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
realCallingPid, userId);
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 419e686e237d..3f075724662f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1827,7 +1827,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- mHistoricalRegistry.clearHistory(uid, packageName);
+ mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory,
+ mHistoricalRegistry, uid, packageName));
}
public void uidRemoved(int uid) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index cb7c568757e5..a546a60e20ef 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -35,7 +35,6 @@ import android.database.ContentObserver;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -51,6 +50,7 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
@@ -338,18 +338,31 @@ public class BiometricService extends SystemService {
private static final boolean DEFAULT_APP_ENABLED = true;
private static final boolean DEFAULT_ALWAYS_REQUIRE_CONFIRMATION = false;
+ // Some devices that shipped before S already have face-specific settings. Instead of
+ // migrating, which is complicated, let's just keep using the existing settings.
+ private final boolean mUseLegacyFaceOnlySettings;
+
+ // Only used for legacy face-only devices
private final Uri FACE_UNLOCK_KEYGUARD_ENABLED =
Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED);
private final Uri FACE_UNLOCK_APP_ENABLED =
Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_APP_ENABLED);
+
+ // Continues to be used, even though it's face-specific.
private final Uri FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
+ // Used for all devices other than legacy face-only devices
+ private final Uri BIOMETRIC_KEYGUARD_ENABLED =
+ Settings.Secure.getUriFor(Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED);
+ private final Uri BIOMETRIC_APP_ENABLED =
+ Settings.Secure.getUriFor(Settings.Secure.BIOMETRIC_APP_ENABLED);
+
private final ContentResolver mContentResolver;
private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks;
- private final Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>();
- private final Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>();
+ private final Map<Integer, Boolean> mBiometricEnabledOnKeyguard = new HashMap<>();
+ private final Map<Integer, Boolean> mBiometricEnabledForApps = new HashMap<>();
private final Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>();
/**
@@ -362,21 +375,44 @@ public class BiometricService extends SystemService {
super(handler);
mContentResolver = context.getContentResolver();
mCallbacks = callbacks;
+
+ final boolean hasFingerprint = context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+ final boolean hasFace = context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_FACE);
+
+ // Use the legacy setting on face-only devices that shipped on or before Q
+ mUseLegacyFaceOnlySettings =
+ Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.Q
+ && hasFace && !hasFingerprint;
+
updateContentObserver();
}
public void updateContentObserver() {
mContentResolver.unregisterContentObserver(this);
- mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
- false /* notifyForDescendents */,
- this /* observer */,
- UserHandle.USER_ALL);
- mContentResolver.registerContentObserver(FACE_UNLOCK_APP_ENABLED,
- false /* notifyForDescendents */,
- this /* observer */,
- UserHandle.USER_ALL);
+
+ if (mUseLegacyFaceOnlySettings) {
+ mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(FACE_UNLOCK_APP_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ } else {
+ mContentResolver.registerContentObserver(BIOMETRIC_KEYGUARD_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(BIOMETRIC_APP_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ }
mContentResolver.registerContentObserver(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
- false /* notifyForDescendents */,
+ false /* notifyForDescendants */,
this /* observer */,
UserHandle.USER_ALL);
}
@@ -384,7 +420,7 @@ public class BiometricService extends SystemService {
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
if (FACE_UNLOCK_KEYGUARD_ENABLED.equals(uri)) {
- mFaceEnabledOnKeyguard.put(userId, Settings.Secure.getIntForUser(
+ mBiometricEnabledOnKeyguard.put(userId, Settings.Secure.getIntForUser(
mContentResolver,
Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED,
DEFAULT_KEYGUARD_ENABLED ? 1 : 0 /* default */,
@@ -394,7 +430,7 @@ public class BiometricService extends SystemService {
notifyEnabledOnKeyguardCallbacks(userId);
}
} else if (FACE_UNLOCK_APP_ENABLED.equals(uri)) {
- mFaceEnabledForApps.put(userId, Settings.Secure.getIntForUser(
+ mBiometricEnabledForApps.put(userId, Settings.Secure.getIntForUser(
mContentResolver,
Settings.Secure.FACE_UNLOCK_APP_ENABLED,
DEFAULT_APP_ENABLED ? 1 : 0 /* default */,
@@ -405,22 +441,45 @@ public class BiometricService extends SystemService {
Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
DEFAULT_ALWAYS_REQUIRE_CONFIRMATION ? 1 : 0 /* default */,
userId) != 0);
+ } else if (BIOMETRIC_KEYGUARD_ENABLED.equals(uri)) {
+ mBiometricEnabledOnKeyguard.put(userId, Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED,
+ DEFAULT_KEYGUARD_ENABLED ? 1 : 0 /* default */,
+ userId) != 0);
+
+ if (userId == ActivityManager.getCurrentUser() && !selfChange) {
+ notifyEnabledOnKeyguardCallbacks(userId);
+ }
+ } else if (BIOMETRIC_APP_ENABLED.equals(uri)) {
+ mBiometricEnabledForApps.put(userId, Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.BIOMETRIC_APP_ENABLED,
+ DEFAULT_APP_ENABLED ? 1 : 0 /* default */,
+ userId) != 0);
}
}
- public boolean getFaceEnabledOnKeyguard() {
- final int user = ActivityManager.getCurrentUser();
- if (!mFaceEnabledOnKeyguard.containsKey(user)) {
- onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, user);
+ public boolean getEnabledOnKeyguard(int userId) {
+ if (!mBiometricEnabledOnKeyguard.containsKey(userId)) {
+ if (mUseLegacyFaceOnlySettings) {
+ onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, userId);
+ } else {
+ onChange(true /* selfChange */, BIOMETRIC_KEYGUARD_ENABLED, userId);
+ }
}
- return mFaceEnabledOnKeyguard.get(user);
+ return mBiometricEnabledOnKeyguard.get(userId);
}
- public boolean getFaceEnabledForApps(int userId) {
- if (!mFaceEnabledForApps.containsKey(userId)) {
- onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId);
+ public boolean getEnabledForApps(int userId) {
+ if (!mBiometricEnabledForApps.containsKey(userId)) {
+ if (mUseLegacyFaceOnlySettings) {
+ onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId);
+ } else {
+ onChange(true /* selfChange */, BIOMETRIC_APP_ENABLED, userId);
+ }
}
- return mFaceEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED);
+ return mBiometricEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED);
}
public boolean getConfirmationAlwaysRequired(@BiometricAuthenticator.Modality int modality,
@@ -442,8 +501,8 @@ public class BiometricService extends SystemService {
void notifyEnabledOnKeyguardCallbacks(int userId) {
List<EnabledOnKeyguardCallback> callbacks = mCallbacks;
for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).notify(BiometricSourceType.FACE,
- mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
+ callbacks.get(i).notify(
+ mBiometricEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
userId);
}
}
@@ -462,9 +521,9 @@ public class BiometricService extends SystemService {
}
}
- void notify(BiometricSourceType sourceType, boolean enabled, int userId) {
+ void notify(boolean enabled, int userId) {
try {
- mCallback.onChanged(sourceType, enabled, userId);
+ mCallback.onChanged(enabled, userId);
} catch (DeadObjectException e) {
Slog.w(TAG, "Death while invoking notify", e);
mEnabledOnKeyguardCallbacks.remove(this);
@@ -747,8 +806,8 @@ public class BiometricService extends SystemService {
mEnabledOnKeyguardCallbacks.add(new EnabledOnKeyguardCallback(callback));
try {
- callback.onChanged(BiometricSourceType.FACE,
- mSettingObserver.getFaceEnabledOnKeyguard(), callingUserId);
+ callback.onChanged(mSettingObserver.getEnabledOnKeyguard(callingUserId),
+ callingUserId);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
}
@@ -1347,6 +1406,9 @@ public class BiometricService extends SystemService {
}
private void dumpInternal(PrintWriter pw) {
+ pw.println("Legacy Settings: " + mSettingObserver.mUseLegacyFaceOnlySettings);
+ pw.println();
+
pw.println("Sensors:");
for (BiometricSensor sensor : mSensors) {
pw.println(" " + sensor);
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 262cb36d7bdb..c4bd18b59745 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -197,17 +197,7 @@ class PreAuthInfo {
private static boolean isEnabledForApp(BiometricService.SettingObserver settingObserver,
@BiometricAuthenticator.Modality int modality, int userId) {
- switch (modality) {
- case TYPE_FINGERPRINT:
- return true;
- case TYPE_IRIS:
- return true;
- case TYPE_FACE:
- return settingObserver.getFaceEnabledForApps(userId);
- default:
- Slog.w(TAG, "Unsupported modality: " + modality);
- return false;
- }
+ return settingObserver.getEnabledForApps(userId);
}
private static boolean isBiometricDisabledByDevicePolicy(
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 1bbcedeb0494..b2d35f45ab44 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -15,9 +15,6 @@
*/
package com.android.server.camera;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.os.Build.VERSION_CODES.M;
import android.annotation.IntDef;
@@ -27,15 +24,12 @@ import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.hardware.CameraSessionStats;
import android.hardware.CameraStreamStats;
import android.hardware.ICameraService;
@@ -43,7 +37,6 @@ import android.hardware.ICameraServiceProxy;
import android.hardware.camera2.CameraMetadata;
import android.hardware.display.DisplayManager;
import android.media.AudioManager;
-import android.metrics.LogMaker;
import android.nfc.INfcAdapter;
import android.os.Binder;
import android.os.Handler;
@@ -60,17 +53,16 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.view.Display;
+import android.view.IDisplayWindowListener;
import android.view.Surface;
+import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.framework.protobuf.nano.MessageNano;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.wm.WindowManagerInternal;
import java.lang.annotation.Retention;
@@ -223,6 +215,37 @@ public class CameraServiceProxy extends SystemService
}
}
+ private final class DisplayWindowListener extends IDisplayWindowListener.Stub {
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ ICameraService cs = getCameraServiceRawLocked();
+ if (cs == null) return;
+
+ try {
+ cs.notifyDisplayConfigurationChange();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not notify cameraserver, remote exception: " + e);
+ // Not much we can do if camera service is dead.
+ }
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayRemoved(int displayId) { }
+
+ @Override
+ public void onFixedRotationStarted(int displayId, int newRotation) { }
+
+ @Override
+ public void onFixedRotationFinished(int displayId) { }
+ }
+
+
+ private final DisplayWindowListener mDisplayWindowListener = new DisplayWindowListener();
+
private final TaskStateHandler mTaskStackListener = new TaskStateHandler();
private final class TaskInfo {
@@ -236,13 +259,12 @@ public class CameraServiceProxy extends SystemService
private final class TaskStateHandler extends TaskStackListener {
private final Object mMapLock = new Object();
- // maps the current top level task id to its corresponding package name
+ // maps the package name to its corresponding current top level task id
@GuardedBy("mMapLock")
private final ArrayMap<String, TaskInfo> mTaskInfoMap = new ArrayMap<>();
@Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
- throws RemoteException {
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
synchronized (mMapLock) {
TaskInfo info = new TaskInfo();
info.frontTaskId = taskInfo.taskId;
@@ -257,7 +279,7 @@ public class CameraServiceProxy extends SystemService
}
@Override
- public void onTaskRemoved(int taskId) throws RemoteException {
+ public void onTaskRemoved(int taskId) {
synchronized (mMapLock) {
for (Map.Entry<String, TaskInfo> entry : mTaskInfoMap.entrySet()){
if (entry.getValue().frontTaskId == taskId) {
@@ -319,7 +341,7 @@ public class CameraServiceProxy extends SystemService
/**
* Gets whether crop-rotate-scale is needed.
*/
- private boolean getNeedCropRotateScale(Context ctx, String packageName,
+ private boolean getNeedCropRotateScale(@NonNull Context ctx, @NonNull String packageName,
@Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing) {
if (taskInfo == null) {
return false;
@@ -334,7 +356,7 @@ public class CameraServiceProxy extends SystemService
// Only enable the crop-rotate-scale workaround if the app targets M or below and is not
// resizeable.
- if ((ctx != null) && !isMOrBelow(ctx, packageName) && taskInfo.isResizeable) {
+ if (!isMOrBelow(ctx, packageName) && taskInfo.isResizeable) {
Slog.v(TAG,
"The activity is N or above and claims to support resizeable-activity. "
+ "Crop-rotate-scale is disabled.");
@@ -372,12 +394,8 @@ public class CameraServiceProxy extends SystemService
taskInfo.isFixedOrientationLandscape);
// We need to do crop-rotate-scale when camera is landscape and activity is portrait or
// vice versa.
- if ((taskInfo.isFixedOrientationPortrait && landscapeCamera)
- || (taskInfo.isFixedOrientationLandscape && !landscapeCamera)) {
- return true;
- } else {
- return false;
- }
+ return (taskInfo.isFixedOrientationPortrait && landscapeCamera)
+ || (taskInfo.isFixedOrientationLandscape && !landscapeCamera);
}
@Override
@@ -389,14 +407,10 @@ public class CameraServiceProxy extends SystemService
return false;
}
- // A few remaining todos:
- // 1) Do the same check when working in WM compatible mode. The sequence needs
- // to be adjusted and use orientation events as triggers for all active camera
- // clients.
- // 2) Modify the sensor orientation in camera characteristics along with any 3A regions
- // in capture requests/results to account for thea physical rotation. The former
- // is somewhat tricky as it assumes that camera clients always check for the current
- // value by retrieving the camera characteristics from the camera device.
+ // TODO: Modify the sensor orientation in camera characteristics along with any 3A
+ // regions in capture requests/results to account for thea physical rotation. The
+ // former is somewhat tricky as it assumes that camera clients always check for the
+ // current value by retrieving the camera characteristics from the camera device.
return getNeedCropRotateScale(mContext, packageName,
mTaskStackListener.getFrontTaskInfo(packageName), sensorOrientation,
lensFacing);
@@ -522,18 +536,25 @@ public class CameraServiceProxy extends SystemService
publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy);
publishLocalService(CameraServiceProxy.class, this);
-
- try {
- ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register task stack listener!");
- }
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
CameraStatsJobService.schedule(mContext);
+
+ try {
+ ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register task stack listener!");
+ }
+
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
+ mDisplayWindowListener);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register display window listener!");
+ }
}
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 9c10814c7591..47c7e3902556 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -45,6 +45,7 @@ import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -67,6 +68,7 @@ import android.view.autofill.AutofillManagerInternal;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextClassifierEvent;
import android.view.textclassifier.TextLinks;
import android.widget.Toast;
@@ -211,9 +213,18 @@ public class ClipboardService extends SystemService {
/** Uids that have already triggered a toast notification for {@link #primaryClip} */
final SparseBooleanArray mNotifiedUids = new SparseBooleanArray();
+ /**
+ * Uids that have already triggered a notification to text classifier for
+ * {@link #primaryClip}.
+ */
+ final SparseBooleanArray mNotifiedTextClassifierUids = new SparseBooleanArray();
+
final HashSet<String> activePermissionOwners
= new HashSet<String>();
+ /** The text classifier session that is used to annotate the text in the primary clip. */
+ TextClassifier mTextClassifier;
+
PerUserClipboard(int userId) {
this.userId = userId;
}
@@ -371,6 +382,7 @@ public class ClipboardService extends SystemService {
addActiveOwnerLocked(intendingUid, pkg);
PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
showAccessNotificationLocked(pkg, intendingUid, intendingUserId, clipboard);
+ notifyTextClassifierLocked(clipboard, pkg, intendingUid);
return clipboard.primaryClip;
}
}
@@ -580,6 +592,7 @@ public class ClipboardService extends SystemService {
}
clipboard.primaryClip = clip;
clipboard.mNotifiedUids.clear();
+ clipboard.mNotifiedTextClassifierUids.clear();
if (clip != null) {
clipboard.primaryClipUid = uid;
clipboard.mPrimaryClipPackage = sourcePackage;
@@ -619,6 +632,11 @@ public class ClipboardService extends SystemService {
@GuardedBy("mLock")
private void startClassificationLocked(@NonNull ClipData clip, @UserIdInt int userId) {
+ if (clip.getItemCount() == 0) {
+ clip.getDescription().setClassificationStatus(
+ ClipDescription.CLASSIFICATION_NOT_PERFORMED);
+ return;
+ }
TextClassifier classifier;
final long ident = Binder.clearCallingIdentity();
try {
@@ -627,17 +645,11 @@ public class ClipboardService extends SystemService {
new TextClassificationContext.Builder(
getContext().getPackageName(),
TextClassifier.WIDGET_TYPE_CLIPBOARD
- ).build()
- );
+ ).build()
+ );
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- if (clip.getItemCount() == 0) {
- clip.getDescription().setClassificationStatus(
- ClipDescription.CLASSIFICATION_NOT_PERFORMED);
- return;
- }
CharSequence text = clip.getItemAt(0).getText();
if (TextUtils.isEmpty(text) || text.length() > mMaxClassificationLength
|| text.length() > classifier.getMaxGenerateLinksTextLength()) {
@@ -645,7 +657,7 @@ public class ClipboardService extends SystemService {
ClipDescription.CLASSIFICATION_NOT_PERFORMED);
return;
}
-
+ getClipboardLocked(userId).mTextClassifier = classifier;
mWorkerHandler.post(() -> doClassification(text, clip, classifier));
}
@@ -653,12 +665,7 @@ public class ClipboardService extends SystemService {
private void doClassification(
CharSequence text, ClipData clip, TextClassifier classifier) {
TextLinks.Request request = new TextLinks.Request.Builder(text).build();
- TextLinks links;
- try {
- links = classifier.generateLinks(request);
- } finally {
- classifier.destroy();
- }
+ TextLinks links = classifier.generateLinks(request);
// Find the highest confidence for each entity in the text.
ArrayMap<String, Float> confidences = new ArrayMap<>();
@@ -979,6 +986,48 @@ public class ClipboardService extends SystemService {
&& item.getIntent() == null;
}
+ /** Potentially notifies the text classifier that an app is accessing a text clip. */
+ @GuardedBy("mLock")
+ private void notifyTextClassifierLocked(
+ PerUserClipboard clipboard, String callingPackage, int callingUid) {
+ if (clipboard.primaryClip == null) {
+ return;
+ }
+ ClipData.Item item = clipboard.primaryClip.getItemAt(0);
+ if (item == null) {
+ return;
+ }
+ if (!isText(clipboard.primaryClip)) {
+ return;
+ }
+ TextClassifier textClassifier = clipboard.mTextClassifier;
+ // Don't notify text classifier if we haven't used it to annotate the text in the clip.
+ if (textClassifier == null) {
+ return;
+ }
+ // Don't notify text classifier if the app reading the clipboard does not have the focus.
+ if (!mWm.isUidFocused(callingUid)) {
+ return;
+ }
+ // Don't notify text classifier again if already notified for this uid and clip.
+ if (clipboard.mNotifiedTextClassifierUids.get(callingUid)) {
+ return;
+ }
+ clipboard.mNotifiedTextClassifierUids.put(callingUid, true);
+ Binder.withCleanCallingIdentity(() -> {
+ TextClassifierEvent.TextLinkifyEvent pasteEvent =
+ new TextClassifierEvent.TextLinkifyEvent.Builder(
+ TextClassifierEvent.TYPE_READ_CLIPBOARD)
+ .setEventContext(new TextClassificationContext.Builder(
+ callingPackage, TextClassifier.WIDGET_TYPE_CLIPBOARD)
+ .build())
+ .setExtras(
+ Bundle.forPair("source_package", clipboard.mPrimaryClipPackage))
+ .build();
+ textClassifier.onTextClassifierEvent(pasteEvent);
+ });
+ }
+
private TextClassificationManager createTextClassificationManagerAsUser(@UserIdInt int userId) {
Context context = getContext().createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
return context.getSystemService(TextClassificationManager.class);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 4d310cbc06bb..584174e237a3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -59,6 +59,7 @@ import com.android.internal.util.WakeupMessage;
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
@@ -281,6 +282,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
*/
public static final int ARG_AGENT_SUCCESS = 1;
+ // How long this network should linger for.
+ private int mLingerDurationMs;
+
// All inactivity timers for this network, sorted by expiry time. A timer is added whenever
// a request is moved to a network with a better score, regardless of whether the network is or
// was lingering or not. An inactivity timer is also added when a network connects
@@ -349,7 +353,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
@NonNull NetworkScore score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
- QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps) {
+ int lingerDurationMs, QosCallbackTracker qosCallbackTracker,
+ ConnectivityService.Dependencies deps) {
Objects.requireNonNull(net);
Objects.requireNonNull(info);
Objects.requireNonNull(lp);
@@ -370,6 +375,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
mHandler = handler;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
+ mLingerDurationMs = lingerDurationMs;
mQosCallbackTracker = qosCallbackTracker;
}
@@ -685,6 +691,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
}
+
+ @Override
+ public void sendLingerDuration(final int durationMs) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_LINGER_DURATION_CHANGED,
+ new Pair<>(NetworkAgentInfo.this, durationMs)).sendToTarget();
+ }
}
/**
@@ -954,13 +966,14 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
/**
* Sets the specified requestId to linger on this network for the specified time. Called by
- * ConnectivityService when the request is moved to another network with a higher score, or
+ * ConnectivityService when any request is moved to another network with a higher score, or
* when a network is newly created.
*
* @param requestId The requestId of the request that no longer need to be served by this
* network. Or {@link NetworkRequest.REQUEST_ID_NONE} if this is the
- * {@code LingerTimer} for a newly created network.
+ * {@code InactivityTimer} for a newly created network.
*/
+ // TODO: Consider creating a dedicated function for nascent network, e.g. start/stopNascent.
public void lingerRequest(int requestId, long now, long duration) {
if (mInactivityTimerForRequest.get(requestId) != null) {
// Cannot happen. Once a request is lingering on a particular network, we cannot
@@ -976,6 +989,19 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
}
/**
+ * Sets the specified requestId to linger on this network for the timeout set when
+ * initializing or modified by {@link #setLingerDuration(int)}. Called by
+ * ConnectivityService when any request is moved to another network with a higher score.
+ *
+ * @param requestId The requestId of the request that no longer need to be served by this
+ * network.
+ * @param now current system timestamp obtained by {@code SystemClock.elapsedRealtime}.
+ */
+ public void lingerRequest(int requestId, long now) {
+ lingerRequest(requestId, now, mLingerDurationMs);
+ }
+
+ /**
* Cancel lingering. Called by ConnectivityService when a request is added to this network.
* Returns true if the given requestId was lingering on this network, false otherwise.
*/
@@ -1012,6 +1038,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
}
if (newExpiry > 0) {
+ // If the newExpiry timestamp is in the past, the wakeup message will fire immediately.
mInactivityMessage = new WakeupMessage(
mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
@@ -1041,8 +1068,33 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
}
/**
- * Return whether the network is just connected and about to be torn down because of not
- * satisfying any request.
+ * Set the linger duration for this NAI.
+ * @param durationMs The new linger duration, in milliseconds.
+ */
+ public void setLingerDuration(final int durationMs) {
+ final long diff = durationMs - mLingerDurationMs;
+ final ArrayList<InactivityTimer> newTimers = new ArrayList<>();
+ for (final InactivityTimer timer : mInactivityTimers) {
+ if (timer.requestId == NetworkRequest.REQUEST_ID_NONE) {
+ // Don't touch nascent timer, re-add as is.
+ newTimers.add(timer);
+ } else {
+ newTimers.add(new InactivityTimer(timer.requestId, timer.expiryMs + diff));
+ }
+ }
+ mInactivityTimers.clear();
+ mInactivityTimers.addAll(newTimers);
+ updateInactivityTimer();
+ mLingerDurationMs = durationMs;
+ }
+
+ /**
+ * Return whether the network satisfies no request, but is still being kept up
+ * because it has just connected less than
+ * {@code ConnectivityService#DEFAULT_NASCENT_DELAY_MS}ms ago and is thus still considered
+ * nascent. Note that nascent mechanism uses inactivity timer which isn't
+ * associated with a request. Thus, use {@link NetworkRequest#REQUEST_ID_NONE} to identify it.
+ *
*/
public boolean isNascent() {
return mInactive && mInactivityTimers.size() == 1
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java
index c123ea75c66c..2b345e5aa79f 100644
--- a/services/core/java/com/android/server/connectivity/NetworkRanker.java
+++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java
@@ -24,6 +24,7 @@ import static android.net.NetworkScore.POLICY_EXITING;
import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY;
import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI;
+import static com.android.net.module.util.CollectionUtils.filter;
import static com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED;
import static com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED;
import static com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD;
@@ -66,18 +67,6 @@ public class NetworkRanker {
public NetworkRanker() { }
- // TODO : move to module utils CollectionUtils.
- @NonNull private static <T> ArrayList<T> filter(@NonNull final Collection<T> source,
- @NonNull final Predicate<T> test) {
- final ArrayList<T> matches = new ArrayList<>();
- for (final T e : source) {
- if (test.test(e)) {
- matches.add(e);
- }
- }
- return matches;
- }
-
/**
* Find the best network satisfying this request among the list of passed networks.
*/
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index e3eeb6c41d9f..3a7220f7592f 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -394,7 +394,8 @@ public final class DreamManagerService extends SystemService {
private void startDreamLocked(final ComponentName name,
final boolean isTest, final boolean canDoze, final int userId) {
- if (Objects.equals(mCurrentDreamName, name)
+ if (!mCurrentDreamIsWaking
+ && Objects.equals(mCurrentDreamName, name)
&& mCurrentDreamIsTest == isTest
&& mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 031c057018ad..754fa25191b0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1253,6 +1253,7 @@ public class HdmiControlService extends SystemService {
void setAudioStatus(boolean mute, int volume) {
if (!isTvDeviceEnabled()
|| !tv().isSystemAudioActivated()
+ || !tv().isArcEstablished() // Don't update TV volume when SAM is on and ARC is off
|| getHdmiCecVolumeControl()
== HdmiControlManager.VOLUME_CONTROL_DISABLED) {
return;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ed8ea186b1d4..7994fccbd650 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4100,13 +4100,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public void removeImeSurfaceFromWindow(IBinder windowToken,
- IVoidResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback, () -> {
- // No permission check, because we'll only execute the request if the calling window is
- // also the current IME client.
- mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
- });
+ public void removeImeSurfaceFromWindowAsync(IBinder windowToken) {
+ // No permission check, because we'll only execute the request if the calling window is
+ // also the current IME client.
+ mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index ef1489b4adf9..62447439003b 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1510,10 +1510,8 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
- public void removeImeSurfaceFromWindow(IBinder windowToken,
- IVoidResultCallback resultCallback) {
+ public void removeImeSurfaceFromWindowAsync(IBinder windowToken) {
reportNotSupported();
- CallbackUtils.onResult(resultCallback, () -> { });
}
@BinderThread
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 6b28fbc9b86c..59f00a2a4bc7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1773,7 +1773,7 @@ public class LockSettingsService extends ILockSettings.Stub {
} else {
final byte[] hashFactor = getHashFactor(password, userHandle);
final byte[] salt = getSalt(userHandle).getBytes();
- String hash = password.passwordToHistoryHash(hashFactor, salt);
+ String hash = password.passwordToHistoryHash(salt, hashFactor);
if (hash == null) {
Slog.e(TAG, "Compute new style password hash failed, fallback to legacy style");
hash = password.legacyPasswordToHash(salt);
@@ -3658,7 +3658,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
- public boolean armRebootEscrow() {
+ public @ArmRebootEscrowErrorCode int armRebootEscrow() {
return mRebootEscrowManager.armRebootEscrowIfNeeded();
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 76ecc1acc7ac..c01523a4bc40 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -18,6 +18,15 @@ package com.android.server.locksettings;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+import static com.android.internal.widget.LockSettingsInternal.ArmRebootEscrowErrorCode;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -577,16 +586,14 @@ class RebootEscrowManager {
mRebootEscrowWanted = false;
setRebootEscrowReady(false);
-
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) {
- Slog.w(TAG,
- "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
- return;
+ Slog.w(TAG, "RebootEscrowProvider is unavailable for clear request");
+ } else {
+ rebootEscrowProvider.clearRebootEscrowKey();
}
clearMetricsStorage();
- rebootEscrowProvider.clearRebootEscrowKey();
List<UserInfo> users = mUserManager.getUsers();
for (UserInfo user : users) {
@@ -596,20 +603,30 @@ class RebootEscrowManager {
mEventLog.addEntry(RebootEscrowEvent.CLEARED_LSKF_REQUEST);
}
- boolean armRebootEscrowIfNeeded() {
+ @ArmRebootEscrowErrorCode int armRebootEscrowIfNeeded() {
if (!mRebootEscrowReady) {
- return false;
+ return ARM_REBOOT_ERROR_ESCROW_NOT_READY;
}
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) {
Slog.w(TAG,
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
- return false;
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_NO_PROVIDER;
}
+ int expectedProviderType = mInjector.serverBasedResumeOnReboot()
+ ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
+ : RebootEscrowProviderInterface.TYPE_HAL;
int actualProviderType = rebootEscrowProvider.getType();
- // TODO(b/183140900) Fail the reboot if provider type mismatches.
+ if (expectedProviderType != actualProviderType) {
+ Slog.w(TAG, "Expect reboot escrow provider " + expectedProviderType
+ + ", but the RoR is prepared with " + actualProviderType
+ + ". Please prepare the RoR again.");
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+ }
RebootEscrowKey escrowKey;
synchronized (mKeyGenerationLock) {
@@ -618,30 +635,38 @@ class RebootEscrowManager {
if (escrowKey == null) {
Slog.e(TAG, "Escrow key is null, but escrow was marked as ready");
- return false;
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_NO_ESCROW_KEY;
}
// We will use the same key from keystore to encrypt the escrow key and escrow data blob.
SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
if (kk == null) {
Slog.e(TAG, "Failed to get encryption key from keystore.");
- return false;
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
}
+
+ // TODO(b/183140900) design detailed errors for store escrow key errors.
+ // We don't clear rebootEscrow here, because some errors may be recoverable, e.g. network
+ // unavailable for server based provider.
boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
- if (armedRebootEscrow) {
- mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
- mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
- USER_SYSTEM);
- // Store the vbmeta digest of both slots.
- mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
- USER_SYSTEM);
- mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
- mInjector.getVbmetaDigest(true), USER_SYSTEM);
- mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
- mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
- }
-
- return armedRebootEscrow;
+ if (!armedRebootEscrow) {
+ return ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+ }
+
+ mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
+ mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
+ USER_SYSTEM);
+ // Store the vbmeta digest of both slots.
+ mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
+ USER_SYSTEM);
+ mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
+ mInjector.getVbmetaDigest(true), USER_SYSTEM);
+ mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
+ mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
+
+ return ARM_REBOOT_ERROR_NONE;
}
private void setRebootEscrowReady(boolean ready) {
@@ -663,10 +688,6 @@ class RebootEscrowManager {
}
boolean clearRebootEscrow() {
- if (mInjector.getRebootEscrowProvider() == null) {
- return false;
- }
-
clearRebootEscrowIfNeeded();
return true;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b10d56b62acc..abcf4fb939e1 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -384,7 +384,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
if (mPlaybackState == null) {
return false;
}
- return mPlaybackState.isActiveState() == expected;
+ return mPlaybackState.isActive() == expected;
}
/**
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 91a66acf433d..dd80e167f0b3 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -636,9 +636,25 @@ public class LauncherAppsService extends SystemService {
Objects.requireNonNull(component);
// All right, create the sender.
- Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
+ final int callingUid = injectBinderCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
+ final PackageManagerInternal pmInt =
+ LocalServices.getService(PackageManagerInternal.class);
+ Intent packageIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT)
+ .setPackage(component.getPackageName());
+ List<ResolveInfo> apps = pmInt.queryIntentActivities(packageIntent,
+ packageIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ callingUid, user.getIdentifier());
+ // ensure that the component is present in the list
+ if (!apps.stream().anyMatch(
+ ri -> component.getClassName().equals(ri.activityInfo.name))) {
+ return null;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
final PendingIntent pi = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 284998203ac0..85c5a5ea84b8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15315,9 +15315,8 @@ public class PackageManagerService extends IPackageManager.Stub
final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions(
REASON_LOCKED_BOOT_COMPLETED);
am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(),
- false, false,
- userId);
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ bOptions.toBundle(), false, false, userId);
// Deliver BOOT_COMPLETED only if user is unlocked
final UserManagerInternal umInternal = mInjector.getUserManagerInternal();
@@ -15327,9 +15326,8 @@ public class PackageManagerService extends IPackageManager.Stub
bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(),
- false, false,
- userId);
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ bOptions.toBundle(), false, false, userId);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -22197,7 +22195,7 @@ public class PackageManagerService extends IPackageManager.Stub
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
am.broadcastIntentWithFeature(null, null, intent, null, null,
- 0, null, null, null, android.app.AppOpsManager.OP_NONE,
+ 0, null, null, null, null, android.app.AppOpsManager.OP_NONE,
null, false, false, userId);
} catch (RemoteException e) {
}
@@ -27810,8 +27808,8 @@ public class PackageManagerService extends IPackageManager.Stub
};
try {
am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, null, false, false,
- UserHandle.USER_ALL);
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE, null, false,
+ false, UserHandle.USER_ALL);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
index 2a17c6d4cec5..3f00a9d999aa 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
@@ -29,6 +29,7 @@ import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.ServiceSpecificException;
import java.util.List;
+import java.util.Objects;
import java.util.UUID;
public class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
@@ -110,6 +111,7 @@ public class DomainVerificationManagerStub extends IDomainVerificationManager.St
public List<DomainOwner> getOwnersForDomain(@NonNull String domain,
@UserIdInt int userId) {
try {
+ Objects.requireNonNull(domain);
return mService.getOwnersForDomain(domain, userId);
} catch (Exception e) {
throw rethrow(e);
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 4ae79a209524..f0fdad016d55 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -742,6 +742,7 @@ public class DomainVerificationService extends SystemService
}
public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
+ Objects.requireNonNull(domain);
mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
userId);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5b333e15fe67..29496b31b4a5 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4492,8 +4492,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public boolean okToAnimate() {
- return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep;
+ public boolean okToAnimate(boolean ignoreScreenOn) {
+ return (ignoreScreenOn || mDefaultDisplayPolicy.isAwake()) && !mDeviceGoingToSleep;
}
/** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d512edfb066a..78b03b2b88e7 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -897,12 +897,13 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public boolean isScreenOn();
/**
+ * @param ignoreScreenOn {@code true} if screen state should be ignored.
* @return whether the device is currently allowed to animate.
*
* Note: this can be true even if it is not appropriate to animate for reasons that are outside
* of the policy's authority.
*/
- boolean okToAnimate();
+ boolean okToAnimate(boolean ignoreScreenOn);
/**
* Tell the policy that the lid switch has changed state.
diff --git a/services/core/java/com/android/server/power/FaceDownDetector.java b/services/core/java/com/android/server/power/FaceDownDetector.java
index 474ce59212ff..816c81ddf305 100644
--- a/services/core/java/com/android/server/power/FaceDownDetector.java
+++ b/services/core/java/com/android/server/power/FaceDownDetector.java
@@ -330,7 +330,9 @@ public class FaceDownDetector implements SensorEventListener {
private boolean isEnabled() {
return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_FEATURE_ENABLED,
- DEFAULT_FEATURE_ENABLED);
+ DEFAULT_FEATURE_ENABLED)
+ && mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_flipToScreenOffEnabled);
}
private float getAccelerationThreshold() {
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 6ea030f56d4d..81a51e290664 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -25,6 +25,8 @@ import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_UNSPECIFIE
import static android.os.RecoverySystem.ResumeOnRebootRebootErrorCode;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+
import android.annotation.IntDef;
import android.content.Context;
import android.content.IntentSender;
@@ -47,6 +49,7 @@ import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.FastImmutableArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -143,7 +146,7 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
*/
@IntDef({ ROR_NEED_PREPARATION,
ROR_SKIP_PREPARATION_AND_NOTIFY,
- ROR_SKIP_PREPARATION_NOT_NOTIFY})
+ ROR_SKIP_PREPARATION_NOT_NOTIFY })
private @interface ResumeOnRebootActionsOnRequest {}
/**
@@ -151,10 +154,43 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
*/
@IntDef({ ROR_NOT_REQUESTED,
ROR_REQUESTED_NEED_CLEAR,
- ROR_REQUESTED_SKIP_CLEAR})
+ ROR_REQUESTED_SKIP_CLEAR })
private @interface ResumeOnRebootActionsOnClear {}
/**
+ * Fatal arm escrow errors from lock settings that means the RoR is in a bad state. So clients
+ * need to prepare RoR again.
+ */
+ static final FastImmutableArraySet<Integer> FATAL_ARM_ESCROW_ERRORS =
+ new FastImmutableArraySet<>(new Integer[]{
+ LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY,
+ LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER,
+ LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH,
+ LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY,
+ LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE,
+ });
+
+ /**
+ * The error details for ArmRebootEscrow. It contains error codes from RecoverySystemService
+ * and LockSettingsService.
+ */
+ static class RebootPreparationError {
+ final @ResumeOnRebootRebootErrorCode int mRebootErrorCode;
+ final int mProviderErrorCode; // The supplemental error code from lock settings
+
+ RebootPreparationError(int rebootErrorCode, int providerErrorCode) {
+ mRebootErrorCode = rebootErrorCode;
+ mProviderErrorCode = providerErrorCode;
+ }
+
+ int getErrorCodeForMetrics() {
+ // The ResumeOnRebootRebootErrorCode are aligned with 1000; so it's safe to add them
+ // for metrics purpose.
+ return mRebootErrorCode + mProviderErrorCode;
+ }
+ }
+
+ /**
* Manages shared preference, i.e. the storage used for metrics reporting.
*/
public static class PreferencesManager {
@@ -709,34 +745,40 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
return true;
}
- private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName,
+ private RebootPreparationError armRebootEscrow(String packageName,
boolean slotSwitch) {
if (packageName == null) {
Slog.w(TAG, "Missing packageName when rebooting with lskf.");
- return RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME;
+ return new RebootPreparationError(
+ RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME, ARM_REBOOT_ERROR_NONE);
}
if (!isLskfCaptured(packageName)) {
- return RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED;
+ return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED,
+ ARM_REBOOT_ERROR_NONE);
}
if (!verifySlotForNextBoot(slotSwitch)) {
- return RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH;
+ return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH,
+ ARM_REBOOT_ERROR_NONE);
}
final long origId = Binder.clearCallingIdentity();
- boolean result;
+ int providerErrorCode;
try {
- result = mInjector.getLockSettingsService().armRebootEscrow();
+ providerErrorCode = mInjector.getLockSettingsService().armRebootEscrow();
} finally {
Binder.restoreCallingIdentity(origId);
}
- if (!result) {
- Slog.w(TAG, "Failure to escrow key for reboot");
- return RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE;
+ if (providerErrorCode != ARM_REBOOT_ERROR_NONE) {
+ Slog.w(TAG, "Failure to escrow key for reboot, providerErrorCode: "
+ + providerErrorCode);
+ return new RebootPreparationError(
+ RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE, providerErrorCode);
}
- return RESUME_ON_REBOOT_REBOOT_ERROR_NONE;
+ return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_NONE,
+ ARM_REBOOT_ERROR_NONE);
}
private boolean useServerBasedRoR() {
@@ -750,7 +792,7 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
}
private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch,
- @ResumeOnRebootRebootErrorCode int errorCode) {
+ RebootPreparationError escrowError) {
int uid = mInjector.getUidFromPackageName(packageName);
boolean serverBased = useServerBasedRoR();
int preparedClientCount;
@@ -773,15 +815,31 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
+ " request count %d, lskf captured count %d, duration since lskf captured"
+ " %d seconds.", packageName, preparedClientCount, requestCount,
lskfCapturedCount, durationSeconds));
- mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
- requestCount, slotSwitch, serverBased, durationSeconds, lskfCapturedCount);
+ mInjector.reportRebootEscrowRebootMetrics(escrowError.getErrorCodeForMetrics(), uid,
+ preparedClientCount, requestCount, slotSwitch, serverBased, durationSeconds,
+ lskfCapturedCount);
+ }
+
+ private void clearRoRPreparationStateOnRebootFailure(RebootPreparationError escrowError) {
+ if (!FATAL_ARM_ESCROW_ERRORS.contains(escrowError.mProviderErrorCode)) {
+ return;
+ }
+
+ Slog.w(TAG, "Clearing resume on reboot states for all clients on arm escrow error: "
+ + escrowError.mProviderErrorCode);
+ synchronized (this) {
+ mCallerPendingRequest.clear();
+ mCallerPreparedForReboot.clear();
+ }
}
private @ResumeOnRebootRebootErrorCode int rebootWithLskfImpl(String packageName, String reason,
boolean slotSwitch) {
- @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch);
- reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode);
+ RebootPreparationError escrowError = armRebootEscrow(packageName, slotSwitch);
+ reportMetricsOnRebootWithLskf(packageName, slotSwitch, escrowError);
+ clearRoRPreparationStateOnRebootFailure(escrowError);
+ @ResumeOnRebootRebootErrorCode int errorCode = escrowError.mRebootErrorCode;
if (errorCode != RESUME_ON_REBOOT_REBOOT_ERROR_NONE) {
return errorCode;
}
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 4f5e8fa9c944..072cc16f680b 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -16,26 +16,22 @@
package com.android.server.timedetector;
-import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
-import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
-import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
-
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.os.Build;
+import android.database.ContentObserver;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;
-import com.android.internal.R;
-import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
import java.time.Instant;
import java.util.Objects;
@@ -43,62 +39,71 @@ import java.util.Objects;
/**
* The real implementation of {@link TimeDetectorStrategyImpl.Environment} used on device.
*/
-public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
-
- private static final String TAG = TimeDetectorService.TAG;
-
- private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
-
- /**
- * Time in the past. If automatic time suggestion is before this point, it's
- * incorrect for sure.
- */
- private static final Instant TIME_LOWER_BOUND = Instant.ofEpochMilli(
- Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
-
- /**
- * By default telephony and network only suggestions are accepted and telephony takes
- * precedence over network.
- */
- private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES =
- { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
- /**
- * If a newly calculated system clock time and the current system clock time differs by this or
- * more the system clock will actually be updated. Used to prevent the system clock being set
- * for only minor differences.
- */
- private final int mSystemClockUpdateThresholdMillis;
+ private static final String LOG_TAG = TimeDetectorService.TAG;
@NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final ContentResolver mContentResolver;
@NonNull private final PowerManager.WakeLock mWakeLock;
@NonNull private final AlarmManager mAlarmManager;
@NonNull private final UserManager mUserManager;
- @NonNull private final int[] mOriginPriorities;
- public EnvironmentImpl(@NonNull Context context) {
+ // @NonNull after setConfigChangeListener() is called.
+ @GuardedBy("this")
+ private ConfigurationChangeListener mConfigChangeListener;
+
+ EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor) {
mContext = Objects.requireNonNull(context);
mContentResolver = Objects.requireNonNull(context.getContentResolver());
+ mHandler = Objects.requireNonNull(handler);
+ mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
PowerManager powerManager = context.getSystemService(PowerManager.class);
mWakeLock = Objects.requireNonNull(
- powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG));
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG));
mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));
mUserManager = Objects.requireNonNull(context.getSystemService(UserManager.class));
- mSystemClockUpdateThresholdMillis =
- SystemProperties.getInt("ro.sys.time_detector_update_diff",
- SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+ // Wire up the config change listeners. All invocations are performed on the mHandler
+ // thread.
+
+ ContentResolver contentResolver = context.getContentResolver();
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ handleAutoTimeDetectionChangedOnHandlerThread();
+ }
+ });
+ }
+
+ /** Internal method for handling the auto time setting being changed. */
+ private void handleAutoTimeDetectionChangedOnHandlerThread() {
+ synchronized (this) {
+ if (mConfigChangeListener == null) {
+ Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
+ }
+ mConfigChangeListener.onChange();
+ }
+ }
- mOriginPriorities = getOriginPriorities(context);
+ @Override
+ public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+ synchronized (this) {
+ mConfigChangeListener = Objects.requireNonNull(listener);
+ }
}
@Override
public int systemClockUpdateThresholdMillis() {
- return mSystemClockUpdateThresholdMillis;
+ return mServiceConfigAccessor.systemClockUpdateThresholdMillis();
}
@Override
@@ -112,12 +117,12 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme
@Override
public Instant autoTimeLowerBound() {
- return TIME_LOWER_BOUND;
+ return mServiceConfigAccessor.autoTimeLowerBound();
}
@Override
public int[] autoOriginPriorities() {
- return mOriginPriorities;
+ return mServiceConfigAccessor.getOriginPriorities();
}
@Override
@@ -131,7 +136,7 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme
@Override
public void acquireWakeLock() {
if (mWakeLock.isHeld()) {
- Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
+ Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " already held");
}
mWakeLock.acquire();
}
@@ -160,7 +165,7 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme
private void checkWakeLockHeld() {
if (!mWakeLock.isHeld()) {
- Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held");
+ Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " not held");
}
}
@@ -168,20 +173,4 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme
UserHandle userHandle = UserHandle.of(userId);
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
}
-
- private static int[] getOriginPriorities(@NonNull Context context) {
- String[] originStrings =
- context.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
- if (originStrings.length == 0) {
- return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
- } else {
- int[] origins = new int[originStrings.length];
- for (int i = 0; i < originStrings.length; i++) {
- int origin = stringToOrigin(originStrings[i]);
- origins[i] = origin;
- }
-
- return origins;
- }
- }
}
diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java
new file mode 100644
index 000000000000..be4432ab61bf
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 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.timedetector;
+
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
+import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
+
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A singleton that provides access to service configuration for time detection. This hides how
+ * configuration is split between static, compile-time config and dynamic, server-pushed flags. It
+ * provides a rudimentary mechanism to signal when values have changed.
+ */
+final class ServiceConfigAccessor {
+
+ private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
+
+ /**
+ * By default telephony and network only suggestions are accepted and telephony takes
+ * precedence over network.
+ */
+ private static final @TimeDetectorStrategy.Origin int[]
+ DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+
+ /**
+ * Time in the past. If an automatic time suggestion is before this point, it is sure to be
+ * incorrect.
+ */
+ private static final Instant TIME_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli(
+ Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
+
+ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
+ new ArraySet<>(new String[] {
+ }));
+
+ private static final Object SLOCK = new Object();
+
+ /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
+ @GuardedBy("SLOCK")
+ @Nullable
+ private static ServiceConfigAccessor sInstance;
+
+ @NonNull private final Context mContext;
+ @NonNull private final ServerFlags mServerFlags;
+ @NonNull private final int[] mOriginPriorities;
+
+ /**
+ * If a newly calculated system clock time and the current system clock time differs by this or
+ * more the system clock will actually be updated. Used to prevent the system clock being set
+ * for only minor differences.
+ */
+ private final int mSystemClockUpdateThresholdMillis;
+
+ private ServiceConfigAccessor(@NonNull Context context) {
+ mContext = Objects.requireNonNull(context);
+ mServerFlags = ServerFlags.getInstance(mContext);
+ mOriginPriorities = getOriginPrioritiesInternal();
+ mSystemClockUpdateThresholdMillis =
+ SystemProperties.getInt("ro.sys.time_detector_update_diff",
+ SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+ }
+
+ /** Returns the singleton instance. */
+ static ServiceConfigAccessor getInstance(Context context) {
+ synchronized (SLOCK) {
+ if (sInstance == null) {
+ sInstance = new ServiceConfigAccessor(context);
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Adds a listener that will be called when server flags related to this class change. The
+ * callbacks are delivered on the main looper thread.
+ *
+ * <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
+ * method.
+ */
+ void addListener(@NonNull ConfigurationChangeListener listener) {
+ mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH);
+ }
+
+ @NonNull
+ int[] getOriginPriorities() {
+ return mOriginPriorities;
+ }
+
+ int systemClockUpdateThresholdMillis() {
+ return mSystemClockUpdateThresholdMillis;
+ }
+
+ Instant autoTimeLowerBound() {
+ return TIME_LOWER_BOUND_DEFAULT;
+ }
+
+ private int[] getOriginPrioritiesInternal() {
+ String[] originStrings =
+ mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
+ if (originStrings.length == 0) {
+ return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
+ } else {
+ int[] origins = new int[originStrings.length];
+ for (int i = 0; i < originStrings.length; i++) {
+ int origin = stringToOrigin(originStrings[i]);
+ origins[i] = origin;
+ }
+
+ return origins;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 27e2ee585a20..20c1c3c8b738 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -27,12 +27,9 @@ import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
-import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
-import android.provider.Settings;
import android.util.IndentingPrintWriter;
import com.android.internal.annotations.VisibleForTesting;
@@ -64,7 +61,16 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@Override
public void onStart() {
- TimeDetectorService service = TimeDetectorService.create(getContext());
+ Context context = getContext();
+ Handler handler = FgThread.getHandler();
+
+ ServiceConfigAccessor serviceConfigAccessor =
+ ServiceConfigAccessor.getInstance(context);
+ TimeDetectorStrategy timeDetectorStrategy =
+ TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
+
+ TimeDetectorService service =
+ new TimeDetectorService(context, handler, timeDetectorStrategy);
// Publish the binder service so it can be accessed from other (appropriately
// permissioned) processes.
@@ -77,28 +83,6 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
@NonNull private final CallerIdentityInjector mCallerIdentityInjector;
- private static TimeDetectorService create(@NonNull Context context) {
- TimeDetectorStrategyImpl.Environment environment = new EnvironmentImpl(context);
- TimeDetectorStrategy timeDetectorStrategy = new TimeDetectorStrategyImpl(environment);
-
- Handler handler = FgThread.getHandler();
- TimeDetectorService timeDetectorService =
- new TimeDetectorService(context, handler, timeDetectorStrategy);
-
- // Wire up event listening.
- ContentResolver contentResolver = context.getContentResolver();
- contentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
- new ContentObserver(handler) {
- @Override
- public void onChange(boolean selfChange) {
- timeDetectorService.handleAutoTimeDetectionChanged();
- }
- });
-
- return timeDetectorService;
- }
-
@VisibleForTesting
public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
@NonNull TimeDetectorStrategy timeDetectorStrategy) {
@@ -185,12 +169,6 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
mHandler.post(() -> mTimeDetectorStrategy.suggestExternalTime(timeSignal));
}
- /** Internal method for handling the auto time setting being changed. */
- @VisibleForTesting
- public void handleAutoTimeDetectionChanged() {
- mHandler.post(mTimeDetectorStrategy::handleAutoTimeConfigChanged);
- }
-
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
@Nullable String[] args) {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index cde66becdee2..be382f0409b1 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -92,12 +92,6 @@ public interface TimeDetectorStrategy extends Dumpable {
/** Returns the configuration that controls time detector behaviour for specified user. */
ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
- /**
- * Handles the auto-time configuration changing For example, when the auto-time setting is
- * toggled on or off.
- */
- void handleAutoTimeConfigChanged();
-
// Utility methods below are to be moved to a better home when one becomes more obvious.
/**
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 289d8d6e648e..db8a59e0ab26 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -29,6 +29,8 @@ import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
+import android.content.Context;
+import android.os.Handler;
import android.os.TimestampedValue;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
@@ -37,6 +39,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.timezonedetector.ArrayMapWithHistory;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ReferenceWithHistory;
import java.time.Instant;
@@ -132,6 +135,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
public interface Environment {
/**
+ * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
+ * changes that could affect time detection. This is invoked during system server setup.
+ */
+ void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);
+
+ /**
* The absolute threshold below which the system clock need not be updated. i.e. if setting
* the system clock would adjust it by less than this (either backwards or forwards) then it
* need not be set.
@@ -178,8 +187,19 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
void releaseWakeLock();
}
+ static TimeDetectorStrategy create(
+ @NonNull Context context, @NonNull Handler handler,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor) {
+
+ TimeDetectorStrategyImpl.Environment environment =
+ new EnvironmentImpl(context, handler, serviceConfigAccessor);
+ return new TimeDetectorStrategyImpl(environment);
+ }
+
+ @VisibleForTesting
TimeDetectorStrategyImpl(@NonNull Environment environment) {
mEnvironment = Objects.requireNonNull(environment);
+ mEnvironment.setConfigChangeListener(this::handleAutoTimeConfigChanged);
}
@Override
@@ -279,8 +299,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
return mEnvironment.configurationInternal(userId);
}
- @Override
- public synchronized void handleAutoTimeConfigChanged() {
+ private synchronized void handleAutoTimeConfigChanged() {
boolean enabled = mEnvironment.isAutoTimeDetectionEnabled();
// When automatic time detection is enabled we update the system clock instantly if we can.
// Conversely, when automatic time detection is disabled we leave the clock as it is.
diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
index 0e5f3bfbb4b1..b84f8a850ba7 100644
--- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
@@ -47,7 +47,7 @@ import java.util.Optional;
/**
* The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
*/
-public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment {
+final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment {
private static final String LOG_TAG = TimeZoneDetectorService.TAG;
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 50d37f42e889..dddb11b7e249 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -133,8 +133,8 @@ public final class ServiceConfigAccessor {
}
/**
- * Adds a listener that will be called server flags related to this class change. The callbacks
- * are delivered on the main looper thread.
+ * Adds a listener that will be called when server flags related to this class change. The
+ * callbacks are delivered on the main looper thread.
*
* <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
* method.
diff --git a/services/core/java/com/android/server/trust/OWNERS b/services/core/java/com/android/server/trust/OWNERS
index b039c4b45447..e2c6ce15b51e 100644
--- a/services/core/java/com/android/server/trust/OWNERS
+++ b/services/core/java/com/android/server/trust/OWNERS
@@ -1 +1 @@
-include /core/java/android/app/trust/OWNERS
+include /core/java/android/service/trust/OWNERS
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index d8a145d9ae33..19fbdbd86099 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -43,6 +43,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import java.util.Collections;
import java.util.HashMap;
@@ -320,6 +321,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
}
+ /** Dumps the state of this snapshot for logging and debugging purposes. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("TelephonySubscriptionSnapshot:");
+ pw.increaseIndent();
+
+ pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap);
+ pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
+
+ pw.decreaseIndent();
+ }
+
@Override
public String toString() {
return "TelephonySubscriptionSnapshot{ "
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index ab9de77005b3..a59b368ec321 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -31,6 +31,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import java.util.ArrayList;
@@ -396,6 +397,18 @@ public class UnderlyingNetworkTracker {
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
}
+ /** Dumps the state of this record for logging and debugging purposes. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("UnderlyingNetworkRecord:");
+ pw.increaseIndent();
+
+ pw.println("mNetwork: " + network);
+ pw.println("mNetworkCapabilities: " + networkCapabilities);
+ pw.println("mLinkProperties: " + linkProperties);
+
+ pw.decreaseIndent();
+ }
+
/** Builder to incrementally construct an UnderlyingNetworkRecord. */
private static class Builder {
@NonNull private final Network mNetwork;
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 7bc6056f91f3..cccb0968fc6a 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
@@ -26,14 +28,21 @@ import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
+import android.net.Uri;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnManager.VcnErrorCode;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -42,9 +51,11 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
@@ -61,6 +72,11 @@ import java.util.Set;
public class Vcn extends Handler {
private static final String TAG = Vcn.class.getSimpleName();
+ private static final int VCN_LEGACY_SCORE_INT = 52;
+
+ private static final List<Integer> CAPS_REQUIRING_MOBILE_DATA =
+ Arrays.asList(NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN);
+
private static final int MSG_EVENT_BASE = 0;
private static final int MSG_CMD_BASE = 100;
@@ -110,6 +126,15 @@ public class Vcn extends Handler {
*/
private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
+ /**
+ * Triggers reevaluation of mobile data enabled conditions.
+ *
+ * <p>Upon this notification, the VCN will check if any of the underlying subIds have mobile
+ * data enabled. If not, the VCN will restart any GatewayConnections providing INTERNET or DUN
+ * with the current mobile data toggle status.
+ */
+ private static final int MSG_EVENT_MOBILE_DATA_TOGGLED = MSG_EVENT_BASE + 5;
+
/** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
@@ -118,6 +143,8 @@ public class Vcn extends Handler {
@NonNull private final Dependencies mDeps;
@NonNull private final VcnNetworkRequestListener mRequestListener;
@NonNull private final VcnCallback mVcnCallback;
+ @NonNull private final VcnContentResolver mContentResolver;
+ @NonNull private final ContentObserver mMobileDataSettingsObserver;
/**
* Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs.
@@ -154,6 +181,8 @@ public class Vcn extends Handler {
// Accessed from different threads, but always under lock in VcnManagementService
private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
+ private boolean mIsMobileDataEnabled = false;
+
public Vcn(
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@@ -177,10 +206,19 @@ public class Vcn extends Handler {
mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback");
mDeps = Objects.requireNonNull(deps, "Missing deps");
mRequestListener = new VcnNetworkRequestListener();
+ mContentResolver = mDeps.newVcnContentResolver(mVcnContext);
+ mMobileDataSettingsObserver = new VcnMobileDataContentObserver(this /* handler */);
+
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
+ mContentResolver.registerContentObserver(
+ uri, true /* notifyForDescendants */, mMobileDataSettingsObserver);
mConfig = Objects.requireNonNull(config, "Missing config");
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
+ // Update mIsMobileDataEnabled before starting handling of NetworkRequests.
+ mIsMobileDataEnabled = getMobileDataStatus();
+
// Register to receive cached and future NetworkRequests
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
}
@@ -230,10 +268,10 @@ public class Vcn extends Handler {
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
@Override
- public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
+ public void onNetworkRequested(@NonNull NetworkRequest request) {
Objects.requireNonNull(request, "Missing request");
- sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, score, providerId, request));
+ sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, request));
}
}
@@ -249,7 +287,7 @@ public class Vcn extends Handler {
handleConfigUpdated((VcnConfig) msg.obj);
break;
case MSG_EVENT_NETWORK_REQUESTED:
- handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
+ handleNetworkRequested((NetworkRequest) msg.obj);
break;
case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
@@ -260,6 +298,9 @@ public class Vcn extends Handler {
case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
handleSafeModeStatusChanged();
break;
+ case MSG_EVENT_MOBILE_DATA_TOGGLED:
+ handleMobileDataToggled();
+ break;
case MSG_CMD_TEARDOWN:
handleTeardown();
break;
@@ -327,25 +368,9 @@ public class Vcn extends Handler {
}
}
- private void handleNetworkRequested(
- @NonNull NetworkRequest request, int score, int providerId) {
+ private void handleNetworkRequested(@NonNull NetworkRequest request) {
Slog.v(getLogTag(), "Received request " + request);
- if (score > getNetworkScore()) {
- if (VDBG) {
- Slog.v(
- getLogTag(),
- "Request already satisfied by higher-scoring ("
- + score
- + ") network from "
- + "provider "
- + providerId
- + ": "
- + request);
- }
- return;
- }
-
// If preexisting VcnGatewayConnection(s) satisfy request, return
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
@@ -366,18 +391,37 @@ public class Vcn extends Handler {
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request);
+ if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) {
+ // Skip; this network does not provide any services if mobile data is disabled.
+ continue;
+ }
+
final VcnGatewayConnection vcnGatewayConnection =
mDeps.newVcnGatewayConnection(
mVcnContext,
mSubscriptionGroup,
mLastSnapshot,
gatewayConnectionConfig,
- new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
+ new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig),
+ mIsMobileDataEnabled);
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
}
}
}
+ private Set<Integer> getExposedCapabilitiesForMobileDataState(
+ VcnGatewayConnectionConfig gatewayConnectionConfig) {
+ if (mIsMobileDataEnabled) {
+ return gatewayConnectionConfig.getAllExposedCapabilities();
+ }
+
+ final Set<Integer> exposedCapsWithoutMobileData =
+ new ArraySet<>(gatewayConnectionConfig.getAllExposedCapabilities());
+ exposedCapsWithoutMobileData.removeAll(CAPS_REQUIRING_MOBILE_DATA);
+
+ return exposedCapsWithoutMobileData;
+ }
+
private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
mVcnGatewayConnections.remove(config);
@@ -396,12 +440,55 @@ public class Vcn extends Handler {
}
}
+ private void handleMobileDataToggled() {
+ final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled;
+ mIsMobileDataEnabled = getMobileDataStatus();
+
+ if (oldMobileDataEnabledStatus != mIsMobileDataEnabled) {
+ // Teardown any GatewayConnections that advertise INTERNET or DUN. If they provide other
+ // services, the VcnGatewayConnections will be restarted without advertising INTERNET or
+ // DUN.
+ for (Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
+ mVcnGatewayConnections.entrySet()) {
+ final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
+ final VcnGatewayConnection gatewayConnection = entry.getValue();
+
+ final Set<Integer> exposedCaps =
+ gatewayConnectionConfig.getAllExposedCapabilities();
+ if (exposedCaps.contains(NET_CAPABILITY_INTERNET)
+ || exposedCaps.contains(NET_CAPABILITY_DUN)) {
+ if (gatewayConnection == null) {
+ Slog.wtf(
+ getLogTag(),
+ "Found gatewayConnectionConfig without GatewayConnection");
+ } else {
+ // TODO(b/184868850): Optimize by restarting NetworkAgents without teardown.
+ gatewayConnection.teardownAsynchronously();
+ }
+ }
+ }
+ }
+ }
+
+ private boolean getMobileDataStatus() {
+ final TelephonyManager genericTelMan =
+ mVcnContext.getContext().getSystemService(TelephonyManager.class);
+
+ for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
+ if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private boolean isRequestSatisfiedByGatewayConnectionConfig(
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
builder.addTransportType(TRANSPORT_CELLULAR);
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- for (int cap : config.getAllExposedCapabilities()) {
+ for (int cap : getExposedCapabilitiesForMobileDataState(config)) {
builder.addCapability(cap);
}
@@ -432,12 +519,20 @@ public class Vcn extends Handler {
pw.decreaseIndent();
}
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public boolean isMobileDataEnabled() {
+ return mIsMobileDataEnabled;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public void setMobileDataEnabled(boolean isMobileDataEnabled) {
+ mIsMobileDataEnabled = isMobileDataEnabled;
+ }
+
/** Retrieves the network score for a VCN Network */
- // Package visibility for use in VcnGatewayConnection
- static int getNetworkScore() {
- // TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in
- // subGrp" value
- return 52;
+ // Package visibility for use in VcnGatewayConnection and VcnNetworkProvider
+ static NetworkScore getNetworkScore() {
+ return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build();
}
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
@@ -485,6 +580,17 @@ public class Vcn extends Handler {
}
}
+ private class VcnMobileDataContentObserver extends ContentObserver {
+ private VcnMobileDataContentObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED));
+ }
+ }
+
/** External dependencies used by Vcn, for injection in tests */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Dependencies {
@@ -494,13 +600,36 @@ public class Vcn extends Handler {
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
VcnGatewayConnectionConfig connectionConfig,
- VcnGatewayStatusCallback gatewayStatusCallback) {
+ VcnGatewayStatusCallback gatewayStatusCallback,
+ boolean isMobileDataEnabled) {
return new VcnGatewayConnection(
vcnContext,
subscriptionGroup,
snapshot,
connectionConfig,
- gatewayStatusCallback);
+ gatewayStatusCallback,
+ isMobileDataEnabled);
+ }
+
+ /** Builds a new VcnContentResolver instance */
+ public VcnContentResolver newVcnContentResolver(VcnContext vcnContext) {
+ return new VcnContentResolver(vcnContext);
+ }
+ }
+
+ /** Proxy Implementation of NetworkAgent, used for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class VcnContentResolver {
+ private final ContentResolver mImpl;
+
+ public VcnContentResolver(VcnContext vcnContext) {
+ mImpl = vcnContext.getContext().getContentResolver();
+ }
+
+ /** Registers the content observer */
+ public void registerContentObserver(
+ @NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer) {
+ mImpl.registerContentObserver(uri, notifyForDescendants, observer);
}
}
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 1d55ba464f51..23fb95b4fa40 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
@@ -47,6 +49,7 @@ import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
+import android.net.NetworkScore;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri;
@@ -517,6 +520,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
@NonNull private final Dependencies mDeps;
@NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
+ private final boolean mIsMobileDataEnabled;
@NonNull private final IpSecManager mIpSecManager;
@@ -626,13 +630,15 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
@NonNull VcnGatewayConnectionConfig connectionConfig,
- @NonNull VcnGatewayStatusCallback gatewayStatusCallback) {
+ @NonNull VcnGatewayStatusCallback gatewayStatusCallback,
+ boolean isMobileDataEnabled) {
this(
vcnContext,
subscriptionGroup,
snapshot,
connectionConfig,
gatewayStatusCallback,
+ isMobileDataEnabled,
new Dependencies());
}
@@ -643,6 +649,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull TelephonySubscriptionSnapshot snapshot,
@NonNull VcnGatewayConnectionConfig connectionConfig,
@NonNull VcnGatewayStatusCallback gatewayStatusCallback,
+ boolean isMobileDataEnabled,
@NonNull Dependencies deps) {
super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
mVcnContext = vcnContext;
@@ -650,6 +657,7 @@ public class VcnGatewayConnection extends StateMachine {
mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
mGatewayStatusCallback =
Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback");
+ mIsMobileDataEnabled = isMobileDataEnabled;
mDeps = Objects.requireNonNull(deps, "Missing deps");
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
@@ -1502,7 +1510,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull VcnNetworkAgent agent,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
- buildNetworkCapabilities(mConnectionConfig, mUnderlying);
+ buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
final LinkProperties lp =
buildConnectedLinkProperties(
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
@@ -1515,7 +1523,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
- buildNetworkCapabilities(mConnectionConfig, mUnderlying);
+ buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
final LinkProperties lp =
buildConnectedLinkProperties(
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
@@ -1843,7 +1851,8 @@ public class VcnGatewayConnection extends StateMachine {
@VisibleForTesting(visibility = Visibility.PRIVATE)
static NetworkCapabilities buildNetworkCapabilities(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
- @Nullable UnderlyingNetworkRecord underlying) {
+ @Nullable UnderlyingNetworkRecord underlying,
+ boolean isMobileDataEnabled) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
builder.addTransportType(TRANSPORT_CELLULAR);
@@ -1853,6 +1862,12 @@ public class VcnGatewayConnection extends StateMachine {
// Add exposed capabilities
for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) {
+ // Skip adding INTERNET or DUN if mobile data is disabled.
+ if (!isMobileDataEnabled
+ && (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN)) {
+ continue;
+ }
+
builder.addCapability(cap);
}
@@ -2040,6 +2055,12 @@ public class VcnGatewayConnection extends StateMachine {
"mNetworkAgent.getNetwork(): "
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
+ pw.println("mUnderlying:");
+ pw.increaseIndent();
+ mUnderlying.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
+
pw.decreaseIndent();
}
@@ -2183,7 +2204,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@NonNull LinkProperties lp,
- @NonNull int score,
+ @NonNull NetworkScore score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
@@ -2324,7 +2345,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@NonNull LinkProperties lp,
- @NonNull int score,
+ @NonNull NetworkScore score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index be0deb57ee76..72cd7880325f 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -16,14 +16,25 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -33,6 +44,7 @@ import com.android.internal.util.IndentingPrintWriter;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
/**
* VCN Network Provider routes NetworkRequests to listeners to bring up tunnels as needed.
@@ -47,15 +59,70 @@ public class VcnNetworkProvider extends NetworkProvider {
private final Set<NetworkRequestListener> mListeners = new ArraySet<>();
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Dependencies mDeps;
+
/**
- * Cache of NetworkRequest(s), scores and network providers, keyed by NetworkRequest
+ * Cache of NetworkRequest(s).
*
* <p>NetworkRequests are immutable once created, and therefore can be used as stable keys.
*/
- private final ArrayMap<NetworkRequest, NetworkRequestEntry> mRequests = new ArrayMap<>();
+ private final Set<NetworkRequest> mRequests = new ArraySet<>();
+
+ public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) {
+ this(context, looper, new Dependencies());
+ }
- public VcnNetworkProvider(Context context, Looper looper) {
- super(context, looper, VcnNetworkProvider.class.getSimpleName());
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public VcnNetworkProvider(
+ @NonNull Context context, @NonNull Looper looper, @NonNull Dependencies dependencies) {
+ super(
+ Objects.requireNonNull(context, "Missing context"),
+ Objects.requireNonNull(looper, "Missing looper"),
+ TAG);
+
+ mContext = context;
+ mHandler = new Handler(looper);
+ mDeps = Objects.requireNonNull(dependencies, "Missing dependencies");
+ }
+
+ /** Registers this VcnNetworkProvider and a generic network offer with ConnectivityService. */
+ public void register() {
+ mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(this);
+ mDeps.registerNetworkOffer(
+ this,
+ Vcn.getNetworkScore(), // score filter
+ buildCapabilityFilter(),
+ new HandlerExecutor(mHandler),
+ new NetworkOfferCallback() {
+ @Override
+ public void onNetworkNeeded(@NonNull NetworkRequest request) {
+ handleNetworkRequested(request);
+ }
+
+ @Override
+ public void onNetworkUnneeded(@NonNull NetworkRequest request) {
+ handleNetworkRequestWithdrawn(request);
+ }
+ });
+ }
+
+ /** Builds the filter for NetworkRequests that can be served by the VcnNetworkProvider. */
+ private NetworkCapabilities buildCapabilityFilter() {
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_TRUSTED)
+ .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NET_CAPABILITY_NOT_VPN)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ for (int cap : VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES) {
+ builder.addCapability(cap);
+ }
+
+ return builder.build();
}
/**
@@ -80,77 +147,37 @@ public class VcnNetworkProvider extends NetworkProvider {
/** Sends all cached NetworkRequest(s) to the specified listener. */
@VisibleForTesting(visibility = Visibility.PACKAGE)
public void resendAllRequests(@NonNull NetworkRequestListener listener) {
- for (NetworkRequestEntry entry : mRequests.values()) {
- notifyListenerForEvent(listener, entry);
+ for (NetworkRequest request : mRequests) {
+ notifyListenerForEvent(listener, request);
}
}
private void notifyListenerForEvent(
- @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
- listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);
+ @NonNull NetworkRequestListener listener, @NonNull NetworkRequest request) {
+ listener.onNetworkRequested(request);
}
- @Override
- public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
+ private void handleNetworkRequested(@NonNull NetworkRequest request) {
if (VDBG) {
- Slog.v(
- TAG,
- "Network requested: Request = "
- + request
- + ", score = "
- + score
- + ", providerId = "
- + providerId);
+ Slog.v(TAG, "Network requested: Request = " + request);
}
- final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId);
-
- // NetworkRequests are immutable once created, and therefore can be used as stable keys.
- mRequests.put(request, entry);
+ mRequests.add(request);
// TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on
// Default Data Sub, or similar)
for (NetworkRequestListener listener : mListeners) {
- notifyListenerForEvent(listener, entry);
+ notifyListenerForEvent(listener, request);
}
}
- @Override
- public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
+ private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
mRequests.remove(request);
}
- private static class NetworkRequestEntry {
- public final NetworkRequest mRequest;
- public final int mScore;
- public final int mProviderId;
-
- private NetworkRequestEntry(@NonNull NetworkRequest request, int score, int providerId) {
- mRequest = Objects.requireNonNull(request, "Missing request");
- mScore = score;
- mProviderId = providerId;
- }
-
- /**
- * Dumps the state of this NetworkRequestEntry for logging and debugging purposes.
- *
- * <p>PII and credentials MUST NEVER be dumped here.
- */
- public void dump(IndentingPrintWriter pw) {
- pw.println("NetworkRequestEntry:");
- pw.increaseIndent();
-
- pw.println("mRequest: " + mRequest);
- pw.println("mScore: " + mScore);
- pw.println("mProviderId: " + mProviderId);
-
- pw.decreaseIndent();
- }
- }
-
// package-private
interface NetworkRequestListener {
- void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId);
+ void onNetworkRequested(@NonNull NetworkRequest request);
}
/**
@@ -163,17 +190,35 @@ public class VcnNetworkProvider extends NetworkProvider {
pw.increaseIndent();
pw.println("mListeners:");
+ pw.increaseIndent();
for (NetworkRequestListener listener : mListeners) {
pw.println(listener);
}
+ pw.decreaseIndent();
pw.println();
- pw.println("mRequests.values:");
- for (NetworkRequestEntry entry : mRequests.values()) {
- entry.dump(pw);
+ pw.println("mRequests:");
+ pw.increaseIndent();
+ for (NetworkRequest request : mRequests) {
+ pw.println(request);
}
+ pw.decreaseIndent();
pw.println();
pw.decreaseIndent();
}
+
+ /** Proxy class for dependencies used for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class Dependencies {
+ /** Registers a given network offer for the given provider. */
+ public void registerNetworkOffer(
+ @NonNull VcnNetworkProvider provider,
+ @NonNull NetworkScore score,
+ @NonNull NetworkCapabilities capabilitiesFilter,
+ @NonNull Executor executor,
+ @NonNull NetworkOfferCallback callback) {
+ provider.registerNetworkOffer(score, capabilitiesFilter, executor, callback);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/vcn/util/MtuUtils.java b/services/core/java/com/android/server/vcn/util/MtuUtils.java
index 49c1a02215e3..5d40cca3e19d 100644
--- a/services/core/java/com/android/server/vcn/util/MtuUtils.java
+++ b/services/core/java/com/android/server/vcn/util/MtuUtils.java
@@ -113,7 +113,6 @@ public class MtuUtils {
return IPV6_MIN_MTU;
}
- boolean hasUnknownAlgorithm = false;
int maxAuthOverhead = 0;
int maxCryptOverhead = 0;
int maxAuthCryptOverhead = 0;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5b4e6a032050..f5cfc9d86cf4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4655,7 +4655,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// still check DC#okToAnimate again if the transition animation is fine to apply.
// TODO(new-app-transition): Rewrite this logic using WM Shell.
final boolean recentsAnimating = isAnimating(PARENTS, ANIMATION_TYPE_RECENTS);
- if (okToAnimate(true /* ignoreFrozen */) && (appTransition.isTransitionSet()
+ if (okToAnimate(true /* ignoreFrozen */, canTurnScreenOn())
+ && (appTransition.isTransitionSet()
|| (recentsAnimating && !isActivityTypeHome()))) {
if (visible) {
displayContent.mOpeningApps.add(this);
@@ -5862,6 +5863,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
nowVisible = true;
lastVisibleTime = SystemClock.uptimeMillis();
mAtmService.scheduleAppGcsLocked();
+ // The nowVisible may be false in onAnimationFinished because the transition animation
+ // was started by starting window but the main window hasn't drawn so the procedure
+ // didn't schedule. Hence also check when nowVisible becomes true (drawn) to avoid the
+ // closing activity having to wait until idle timeout to be stopped or destroyed if the
+ // next activity won't report idle (e.g. repeated view animation).
+ mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
}
}
@@ -6678,26 +6685,26 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// traverse the copy.
final ArrayList<WindowState> children = new ArrayList<>(mChildren);
children.forEach(WindowState::onExitAnimationDone);
+ // The starting window could transfer to another activity after app transition started, in
+ // that case the latest top activity might not receive exit animation done callback if the
+ // starting window didn't applied exit animation success. Notify animation finish to the
+ // starting window if needed.
+ if (task != null && startingMoved) {
+ final WindowState transferredStarting = task.getWindow(w ->
+ w.mAttrs.type == TYPE_APPLICATION_STARTING);
+ if (transferredStarting != null && transferredStarting.mAnimatingExit
+ && !transferredStarting.isSelfAnimating(0 /* flags */,
+ ANIMATION_TYPE_WINDOW_ANIMATION)) {
+ transferredStarting.onExitAnimationDone();
+ }
+ }
getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
scheduleAnimation();
- if (!mTaskSupervisor.mStoppingActivities.isEmpty()
- || !mTaskSupervisor.mFinishingActivities.isEmpty()) {
- if (mRootWindowContainer.allResumedActivitiesIdle()) {
- // If all activities are already idle then we now need to make sure we perform
- // the full stop of this activity. This is because we won't do that while they
- // are still waiting for the animation to finish.
- mTaskSupervisor.scheduleIdle();
- } else if (mRootWindowContainer.allResumedActivitiesVisible()) {
- // If all resumed activities are already visible (and should be drawn, see
- // updateReportedVisibility ~ nowVisible) but not idle, we still schedule to
- // process the stopping and finishing activities because the transition is done.
- // This also avoids if the next activity never reports idle (e.g. animating view),
- // the previous will need to wait until idle timeout to be stopped or destroyed.
- mTaskSupervisor.scheduleProcessStoppingAndFinishingActivities();
- }
- }
+ // Schedule to handle the stopping and finishing activities which the animation is done
+ // because the activities which were animating have not been stopped yet.
+ mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bdde3692ef53..2b1cf395dcd7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2027,7 +2027,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
final void scheduleIdle() {
- mHandler.sendEmptyMessage(IDLE_NOW_MSG);
+ if (!mHandler.hasMessages(IDLE_NOW_MSG)) {
+ mHandler.sendEmptyMessage(IDLE_NOW_MSG);
+ }
}
/**
@@ -2115,8 +2117,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
}
- void scheduleProcessStoppingAndFinishingActivities() {
- if (!mHandler.hasMessages(PROCESS_STOPPING_AND_FINISHING_MSG)) {
+ void scheduleProcessStoppingAndFinishingActivitiesIfNeeded() {
+ if ((!mStoppingActivities.isEmpty() || !mFinishingActivities.isEmpty())
+ && !mHandler.hasMessages(PROCESS_STOPPING_AND_FINISHING_MSG)
+ && mRootWindowContainer.allResumedActivitiesVisible()) {
mHandler.sendEmptyMessage(PROCESS_STOPPING_AND_FINISHING_MSG);
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 99289e0139b0..394ae7e94b72 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1679,11 +1679,15 @@ public class AppTransition implements Dump {
|| transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
}
- static boolean isKeyguardTransitOld(@TransitionOldType int transit) {
- return isKeyguardGoingAwayTransitOld(transit) || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+ static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
+ return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
|| transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
+ static boolean isKeyguardTransitOld(@TransitionOldType int transit) {
+ return isKeyguardGoingAwayTransitOld(transit) || isKeyguardOccludeTransitOld(transit);
+ }
+
static boolean isTaskTransitOld(@TransitionOldType int transit) {
return isTaskOpenTransitOld(transit)
|| transit == TRANSIT_OLD_TASK_CLOSE
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 9a43ca8794da..e7c51a4ac65a 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -68,7 +68,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Trace;
import android.util.ArrayMap;
@@ -428,43 +427,37 @@ public class AppTransitionController {
return mainWindow != null ? mainWindow.mAttrs : null;
}
- RemoteAnimationAdapter getRemoteAnimationOverride(@NonNull WindowContainer container,
+ RemoteAnimationAdapter getRemoteAnimationOverride(@Nullable WindowContainer container,
@TransitionOldType int transit, ArraySet<Integer> activityTypes) {
- final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition();
- if (definition != null) {
- final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
- if (adapter != null) {
- return adapter;
- }
- }
- if (mRemoteAnimationDefinition != null) {
- final RemoteAnimationAdapter adapter = mRemoteAnimationDefinition.getAdapter(
- transit, activityTypes);
- if (adapter != null) {
- return adapter;
+ if (container != null) {
+ final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition();
+ if (definition != null) {
+ final RemoteAnimationAdapter adapter = definition.getAdapter(transit,
+ activityTypes);
+ if (adapter != null) {
+ return adapter;
+ }
}
}
- return null;
+ return mRemoteAnimationDefinition != null
+ ? mRemoteAnimationDefinition.getAdapter(transit, activityTypes)
+ : null;
}
/**
* Overrides the pending transition with the remote animation defined for the transition in the
* set of defined remote animations in the app window token.
*/
- private void overrideWithRemoteAnimationIfSet(ActivityRecord animLpActivity,
+ private void overrideWithRemoteAnimationIfSet(@Nullable ActivityRecord animLpActivity,
@TransitionOldType int transit, ArraySet<Integer> activityTypes) {
if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) {
// The crash transition has higher priority than any involved remote animations.
return;
}
- if (animLpActivity == null) {
- return;
- }
final RemoteAnimationAdapter adapter =
getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
if (adapter != null) {
- animLpActivity.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
- adapter);
+ mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4b735c2c218e..c44f4e3cbd71 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4436,9 +4436,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
boolean okToDisplay(boolean ignoreFrozen) {
+ return okToDisplay(ignoreFrozen, false /* ignoreScreenOn */);
+ }
+
+ boolean okToDisplay(boolean ignoreFrozen, boolean ignoreScreenOn) {
if (mDisplayId == DEFAULT_DISPLAY) {
return (!mWmService.mDisplayFrozen || ignoreFrozen)
- && mWmService.mDisplayEnabled && mWmService.mPolicy.isScreenOn();
+ && mWmService.mDisplayEnabled
+ && (ignoreScreenOn || mWmService.mPolicy.isScreenOn());
}
return mDisplayInfo.state == Display.STATE_ON;
}
@@ -4448,8 +4453,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
boolean okToAnimate(boolean ignoreFrozen) {
- return okToDisplay(ignoreFrozen) &&
- (mDisplayId != DEFAULT_DISPLAY || mWmService.mPolicy.okToAnimate());
+ return okToAnimate(ignoreFrozen, false /* ignoreScreenOn */);
+ }
+
+ boolean okToAnimate(boolean ignoreFrozen, boolean ignoreScreenOn) {
+ return okToDisplay(ignoreFrozen, ignoreScreenOn)
+ && (mDisplayId != DEFAULT_DISPLAY
+ || mWmService.mPolicy.okToAnimate(ignoreScreenOn));
}
static final class TaskForResizePointSearchResult {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 9ff701cafd66..e1fc75e6fd9f 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -731,7 +731,7 @@ public class DisplayRotation {
private RotationAnimationPair selectRotationAnimation() {
// If the screen is off or non-interactive, force a jumpcut.
final boolean forceJumpcut = !mDisplayPolicy.isScreenOnFully()
- || !mService.mPolicy.okToAnimate();
+ || !mService.mPolicy.okToAnimate(false /* ignoreScreenOn */);
final WindowState topFullscreen = mDisplayPolicy.getTopFullscreenOpaqueWindow();
if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation topFullscreen="
+ topFullscreen + " rotationAnimation="
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 20216c3afcd4..8ff9fbaa3995 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -341,11 +341,10 @@ class KeyguardController {
/**
* Called when occluded state changed.
*
- * @param currentTaskControllingOcclusion the task that controls the state whether keyguard
- * should be occluded. That is the task to be shown on top of keyguard if it requests so.
+ * @param topActivity the activity that controls the state whether keyguard should
+ * be occluded. That is the activity to be shown on top of keyguard if it requests so.
*/
- private void handleOccludedChanged(
- int displayId, @Nullable Task currentTaskControllingOcclusion) {
+ private void handleOccludedChanged(int displayId, @Nullable ActivityRecord topActivity) {
// TODO(b/113840485): Handle app transition for individual display, and apply occluded
// state change to secondary displays.
// For now, only default display fully supports occluded change. Other displays only
@@ -364,6 +363,13 @@ class KeyguardController {
isDisplayOccluded(DEFAULT_DISPLAY)
? TRANSIT_KEYGUARD_OCCLUDE
: TRANSIT_KEYGUARD_UNOCCLUDE);
+ // When the occluding activity also turns on the display, visibility of the activity
+ // can be committed before KEYGUARD_OCCLUDE transition is handled.
+ // Set mRequestForceTransition flag to make sure that the app transition animation
+ // is applied for such case.
+ if (topActivity != null) {
+ topActivity.mRequestForceTransition = true;
+ }
updateKeyguardSleepToken(DEFAULT_DISPLAY);
mWindowManager.executeAppTransition();
} finally {
@@ -580,7 +586,7 @@ class KeyguardController {
if (lastOccluded != mOccluded) {
occludingChange = true;
- controller.handleOccludedChanged(mDisplayId, task);
+ controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
}
if (occludingChange || turningScreenOn) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index f851e3559def..67bc7af6dc28 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -121,7 +121,10 @@ class RemoteAnimationController implements DeathRecipient {
// Create the app targets
final RemoteAnimationTarget[] appTargets = createAppAnimations();
- if (appTargets.length == 0) {
+ if (appTargets.length == 0 && !AppTransition.isKeyguardOccludeTransitOld(transit)) {
+ // Keyguard occlude transition can be executed before the occluding activity becomes
+ // visible. Even in this case, KeyguardService expects to receive binder call, so we
+ // don't cancel remote animation.
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
"goodToGo(): No apps to animate, mPendingAnimations=%d",
mPendingAnimations.size());
@@ -133,12 +136,16 @@ class RemoteAnimationController implements DeathRecipient {
// Create the remote wallpaper animation targets (if any)
final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
- // TODO(bc-unlock): Create the remote non app animation targets (if any)
+ // Create the remote non app animation targets (if any)
final RemoteAnimationTarget[] nonAppTargets = createNonAppWindowAnimations(transit);
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
try {
linkToDeathOfRunner();
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): onAnimationStart,"
+ + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
+ AppTransition.appTransitionOldToString(transit), appTargets.length,
+ wallpaperTargets.length, nonAppTargets.length);
mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets,
wallpaperTargets, nonAppTargets, mFinishedCallback);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 070a7252a3bf..191c3a117e85 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2796,6 +2796,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return dc != null && dc.okToAnimate(ignoreFrozen);
}
+ boolean okToAnimate(boolean ignoreFrozen, boolean ignoreScreenOn) {
+ final DisplayContent dc = getDisplayContent();
+ return dc != null && dc.okToAnimate(ignoreFrozen, ignoreScreenOn);
+ }
+
@Override
public void commitPendingTransaction() {
scheduleAnimation();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 43dceeda3026..67edde140c04 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1183,7 +1183,8 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
- SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
+ new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,
+ SurfaceControl.Builder::new);
}
/**
@@ -1193,12 +1194,14 @@ public class WindowManagerService extends IWindowManager.Stub
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
- ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
+ ActivityTaskManagerService atm, DisplayWindowSettingsProvider
+ displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
- atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0);
+ atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
+ surfaceControlFactory), 0);
return sInstance;
}
@@ -1220,7 +1223,8 @@ public class WindowManagerService extends IWindowManager.Stub
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
- ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
+ ActivityTaskManagerService atm, DisplayWindowSettingsProvider
+ displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
installLock(this, INDEX_WINDOW);
@@ -1370,7 +1374,7 @@ public class WindowManagerService extends IWindowManager.Stub
final String displaySettingsPath = Settings.Global.getString(resolver,
DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
- mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider();
+ mDisplayWindowSettingsProvider = displayWindowSettingsProvider;
if (displaySettingsPath != null) {
mDisplayWindowSettingsProvider.setBaseSettingsFilePath(displaySettingsPath);
}
@@ -1736,8 +1740,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
// Switch to listen to the {@link WindowToken token}'s configuration changes when
- // adding a window to the window context.
- if (mWindowContextListenerController.hasListener(windowContextToken)) {
+ // adding a window to the window context. Filter sub window type here because the sub
+ // window must be attached to the parent window, which is attached to the window context
+ // created window token.
+ if (!win.isChildWindow()
+ && mWindowContextListenerController.hasListener(windowContextToken)) {
final int windowContextType = mWindowContextListenerController
.getWindowType(windowContextToken);
if (type != windowContextType) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1ba57fd0251b..ddcb2bf7be22 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -173,6 +173,7 @@ import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.FullyManagedDeviceProvisioningParams;
import android.app.admin.ManagedProfileProvisioningParams;
import android.app.admin.NetworkEvent;
+import android.app.admin.ParcelableGranteeMap;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
import android.app.admin.SecurityLog;
@@ -278,6 +279,7 @@ import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.text.TextUtils;
import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
@@ -5649,41 +5651,33 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public List<String> getKeyPairGrants(String callerPackage, String alias) {
+ public ParcelableGranteeMap getKeyPairGrants(String callerPackage, String alias) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
Preconditions.checkCallAuthorization(canManageCertificates(caller));
- return mInjector.binderWithCleanCallingIdentity(() -> {
+ final ArrayMap<Integer, Set<String>> result = new ArrayMap<>();
+ mInjector.binderWithCleanCallingIdentity(() -> {
try (KeyChainConnection keyChainConnection =
KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
- final List<String> result = new ArrayList<>();
final int[] granteeUids = keyChainConnection.getService().getGrants(alias);
final PackageManager pm = mInjector.getPackageManager(caller.getUserId());
- // TODO: Return Set<Set<String>> when AIDL supports it: b/136048684
- // Public API returns a set of sets, where each internal set contains all package
- // names corresponding to the same UID. For now a set of sets is marshalled as a
- // null-separated list.
for (final int uid : granteeUids) {
final String[] packages = pm.getPackagesForUid(uid);
if (packages == null) {
Slogf.wtf(LOG_TAG, "No packages found for uid " + uid);
continue;
}
- if (!result.isEmpty()) {
- result.add(null);
- }
- result.addAll(Arrays.asList(packages));
+ result.put(uid, new ArraySet<String>(packages));
}
- return result;
} catch (RemoteException e) {
Slogf.e(LOG_TAG, "Querying keypair grants", e);
} catch (InterruptedException e) {
Slogf.w(LOG_TAG, "Interrupted while querying keypair grants", e);
Thread.currentThread().interrupt();
}
- return Collections.emptyList();
});
+ return new ParcelableGranteeMap(result);
}
/**
@@ -8125,20 +8119,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ " as device owner for user " + userId);
return false;
}
- if (admin == null
- || !isPackageInstalledForUser(admin.getPackageName(), userId)) {
- throw new IllegalArgumentException("Invalid component " + admin
- + " for device owner");
- }
+ Preconditions.checkArgument(admin != null);
final CallerIdentity caller = getCallerIdentity();
synchronized (getLockObject()) {
enforceCanSetDeviceOwnerLocked(caller, admin, userId);
+ Preconditions.checkArgument(isPackageInstalledForUser(admin.getPackageName(), userId),
+ "Invalid component " + admin + " for device owner");
final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId);
- if (activeAdmin == null
- || getUserData(userId).mRemovingAdmins.contains(admin)) {
- throw new IllegalArgumentException("Not active admin: " + admin);
- }
+ Preconditions.checkArgument(activeAdmin != null && !getUserData(
+ userId).mRemovingAdmins.contains(admin), "Not active admin: " + admin);
// Shutting down backup manager service permanently.
toggleBackupServiceActive(UserHandle.USER_SYSTEM, /* makeActive= */ false);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 912b8cad952c..4c4c5821a2db 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -384,6 +384,7 @@ public final class SystemServer implements Dumpable {
private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService";
private static final String GAME_MANAGER_SERVICE_CLASS =
"com.android.server.app.GameManagerService$Lifecycle";
+ private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -2637,6 +2638,12 @@ public final class SystemServer implements Dumpable {
LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
t.traceEnd();
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
+ t.traceBegin("UwbService");
+ mSystemServiceManager.startService(UWB_SERVICE_CLASS);
+ t.traceEnd();
+ }
+
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java
index 14c02d53efad..0a5a3bff3676 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java
@@ -20,11 +20,14 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager;
+import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainVerificationManager;
import com.android.server.pm.verify.domain.DomainVerificationService;
+import java.util.List;
import java.util.Set;
+import java.util.SortedSet;
import java.util.UUID;
/**
@@ -58,4 +61,14 @@ class DomainVerificationJavaUtil {
throws PackageManager.NameNotFoundException {
return manager.setDomainVerificationUserSelection(domainSetId, domains, enabled);
}
+
+ static SortedSet<DomainOwner> getOwnersForDomain(@NonNull DomainVerificationManager manager,
+ @Nullable String domain) {
+ return manager.getOwnersForDomain(domain);
+ }
+
+ static List<DomainOwner> getOwnersForDomain(@NonNull DomainVerificationService service,
+ @Nullable String domain, @UserIdInt int userId) {
+ return service.getOwnersForDomain(domain, userId);
+ }
}
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 7fea4ee42317..3838f68fcf22 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
@@ -292,8 +292,17 @@ class DomainVerificationManagerApiTest {
val manager0 = makeManager(service, 0)
val manager1 = makeManager(service, 1)
- assertThat(service.getOwnersForDomain(DOMAIN_1, 0)).isEmpty()
- assertThat(manager0.getOwnersForDomain(DOMAIN_1)).isEmpty()
+ listOf(DOMAIN_1, "").forEach {
+ assertThat(service.getOwnersForDomain(it, 0)).isEmpty()
+ assertThat(manager0.getOwnersForDomain(it)).isEmpty()
+ }
+
+ assertFailsWith(NullPointerException::class) {
+ DomainVerificationJavaUtil.getOwnersForDomain(service, null, 0)
+ }
+ assertFailsWith(NullPointerException::class) {
+ DomainVerificationJavaUtil.getOwnersForDomain(manager0, null)
+ }
assertThat(
service.setStatus(
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index edfc21d47767..7654093f9e7e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -2223,7 +2223,11 @@ public class AlarmManagerServiceTest {
}
@Test
- public void minWindow() {
+ public void minWindowChangeEnabled() {
+ doReturn(true).when(
+ () -> CompatChanges.isChangeEnabled(
+ eq(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS),
+ anyString(), any(UserHandle.class)));
final long minWindow = 73;
setDeviceConfigLong(KEY_MIN_WINDOW, minWindow);
@@ -2239,6 +2243,26 @@ public class AlarmManagerServiceTest {
}
@Test
+ public void minWindowChangeDisabled() {
+ doReturn(false).when(
+ () -> CompatChanges.isChangeEnabled(
+ eq(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS),
+ anyString(), any(UserHandle.class)));
+ final long minWindow = 73;
+ setDeviceConfigLong(KEY_MIN_WINDOW, minWindow);
+
+ // 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC.
+ for (int window = 1; window <= minWindow; window++) {
+ final PendingIntent pi = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, 0, window, pi, 0, 0, TEST_CALLING_UID, null);
+
+ assertEquals(1, mService.mAlarmStore.size());
+ final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0);
+ assertEquals(window, a.windowLength);
+ }
+ }
+
+ @Test
public void denyListPackagesAdded() {
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{"p1", "p2", "p3"});
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, "p2,p4,p5");
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
index 924ad7f3f5a1..76f7e80a3412 100644
--- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -35,7 +35,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
-import android.util.ArrayMap;
import android.util.LongSparseArray;
import androidx.test.InstrumentationRegistry;
@@ -68,7 +67,6 @@ public class BlobStoreManagerServiceTest {
private File mBlobsDir;
private LongSparseArray<BlobStoreSession> mUserSessions;
- private ArrayMap<BlobHandle, BlobMetadata> mUserBlobs;
private static final String TEST_PKG1 = "com.example1";
private static final String TEST_PKG2 = "com.example2";
@@ -99,10 +97,8 @@ public class BlobStoreManagerServiceTest {
mHandler = new TestHandler(Looper.getMainLooper());
mService = new BlobStoreManagerService(mContext, new TestInjector());
mUserSessions = new LongSparseArray<>();
- mUserBlobs = new ArrayMap<>();
mService.addUserSessionsForTest(mUserSessions, UserHandle.myUserId());
- mService.addUserBlobsForTest(mUserBlobs, UserHandle.myUserId());
}
@After
@@ -147,7 +143,7 @@ public class BlobStoreManagerServiceTest {
final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobId1, blobFile1,
blobHandle1, true /* hasLeases */);
doReturn(true).when(blobMetadata1).isACommitter(TEST_PKG1, TEST_UID1);
- mUserBlobs.put(blobHandle1, blobMetadata1);
+ addBlob(blobHandle1, blobMetadata1);
final long blobId2 = 347;
final File blobFile2 = mock(File.class);
@@ -156,7 +152,7 @@ public class BlobStoreManagerServiceTest {
final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2,
blobHandle2, false /* hasLeases */);
doReturn(false).when(blobMetadata2).isACommitter(TEST_PKG1, TEST_UID1);
- mUserBlobs.put(blobHandle2, blobMetadata2);
+ addBlob(blobHandle2, blobMetadata2);
final long blobId3 = 49875;
final File blobFile3 = mock(File.class);
@@ -165,7 +161,7 @@ public class BlobStoreManagerServiceTest {
final BlobMetadata blobMetadata3 = createBlobMetadataMock(blobId3, blobFile3,
blobHandle3, true /* hasLeases */);
doReturn(true).when(blobMetadata3).isACommitter(TEST_PKG1, TEST_UID1);
- mUserBlobs.put(blobHandle3, blobMetadata3);
+ addBlob(blobHandle3, blobMetadata3);
mService.addActiveIdsForTest(sessionId1, sessionId2, sessionId3, sessionId4,
blobId1, blobId2, blobId3);
@@ -197,10 +193,10 @@ public class BlobStoreManagerServiceTest {
verify(blobMetadata2).destroy();
verify(blobMetadata3).destroy();
- assertThat(mUserBlobs.size()).isEqualTo(1);
- assertThat(mUserBlobs.get(blobHandle1)).isNotNull();
- assertThat(mUserBlobs.get(blobHandle2)).isNull();
- assertThat(mUserBlobs.get(blobHandle3)).isNull();
+ assertThat(mService.getBlobsCountForTest()).isEqualTo(1);
+ assertThat(mService.getBlobForTest(blobHandle1)).isNotNull();
+ assertThat(mService.getBlobForTest(blobHandle2)).isNull();
+ assertThat(mService.getBlobForTest(blobHandle3)).isNull();
assertThat(mService.getActiveIdsForTest()).containsExactly(
sessionId2, sessionId3, blobId1);
@@ -293,7 +289,7 @@ public class BlobStoreManagerServiceTest {
"label1", System.currentTimeMillis() - 2000, "tag1");
final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobId1, blobFile1, blobHandle1,
true /* hasLeases */);
- mUserBlobs.put(blobHandle1, blobMetadata1);
+ addBlob(blobHandle1, blobMetadata1);
final long blobId2 = 78974;
final File blobFile2 = mock(File.class);
@@ -301,7 +297,7 @@ public class BlobStoreManagerServiceTest {
"label2", System.currentTimeMillis() + 30000, "tag2");
final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2, blobHandle2,
true /* hasLeases */);
- mUserBlobs.put(blobHandle2, blobMetadata2);
+ addBlob(blobHandle2, blobMetadata2);
final long blobId3 = 97;
final File blobFile3 = mock(File.class);
@@ -309,7 +305,7 @@ public class BlobStoreManagerServiceTest {
"label3", System.currentTimeMillis() + 4400000, "tag3");
final BlobMetadata blobMetadata3 = createBlobMetadataMock(blobId3, blobFile3, blobHandle3,
false /* hasLeases */);
- mUserBlobs.put(blobHandle3, blobMetadata3);
+ addBlob(blobHandle3, blobMetadata3);
mService.addActiveIdsForTest(blobId1, blobId2, blobId3);
@@ -321,8 +317,8 @@ public class BlobStoreManagerServiceTest {
verify(blobMetadata2, never()).destroy();
verify(blobMetadata3).destroy();
- assertThat(mUserBlobs.size()).isEqualTo(1);
- assertThat(mUserBlobs.get(blobHandle2)).isNotNull();
+ assertThat(mService.getBlobsCountForTest()).isEqualTo(1);
+ assertThat(mService.getBlobForTest(blobHandle2)).isNotNull();
assertThat(mService.getActiveIdsForTest()).containsExactly(blobId2);
assertThat(mService.getKnownIdsForTest()).containsExactly(blobId1, blobId2, blobId3);
@@ -336,21 +332,21 @@ public class BlobStoreManagerServiceTest {
doReturn(size1).when(blobMetadata1).getSize();
doReturn(true).when(blobMetadata1).isALeasee(TEST_PKG1, TEST_UID1);
doReturn(true).when(blobMetadata1).isALeasee(TEST_PKG2, TEST_UID2);
- mUserBlobs.put(mock(BlobHandle.class), blobMetadata1);
+ addBlob(mock(BlobHandle.class), blobMetadata1);
final BlobMetadata blobMetadata2 = mock(BlobMetadata.class);
final long size2 = 89475;
doReturn(size2).when(blobMetadata2).getSize();
doReturn(false).when(blobMetadata2).isALeasee(TEST_PKG1, TEST_UID1);
doReturn(true).when(blobMetadata2).isALeasee(TEST_PKG2, TEST_UID2);
- mUserBlobs.put(mock(BlobHandle.class), blobMetadata2);
+ addBlob(mock(BlobHandle.class), blobMetadata2);
final BlobMetadata blobMetadata3 = mock(BlobMetadata.class);
final long size3 = 328732;
doReturn(size3).when(blobMetadata3).getSize();
doReturn(true).when(blobMetadata3).isALeasee(TEST_PKG1, TEST_UID1);
doReturn(false).when(blobMetadata3).isALeasee(TEST_PKG2, TEST_UID2);
- mUserBlobs.put(mock(BlobHandle.class), blobMetadata3);
+ addBlob(mock(BlobHandle.class), blobMetadata3);
// Verify usage is calculated correctly
assertThat(mService.getTotalUsageBytesLocked(TEST_UID1, TEST_PKG1))
@@ -388,6 +384,11 @@ public class BlobStoreManagerServiceTest {
return blobMetadata;
}
+ private void addBlob(BlobHandle blobHandle, BlobMetadata blobMetadata) {
+ doReturn(blobHandle).when(blobMetadata).getBlobHandle();
+ mService.addBlobLocked(blobMetadata);
+ }
+
private class TestHandler extends Handler {
TestHandler(Looper looper) {
super(looper);
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index d7fbd4913b2c..9d055e0d431f 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -37,6 +37,7 @@ android_test {
"services.net",
"services.people",
"services.usage",
+ "services.uwb",
"guava",
"androidx.test.core",
"androidx.test.ext.truth",
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index 5bef877e2f39..e9b5b6243089 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -184,6 +184,7 @@ public class BroadcastRecordTest {
false /* callerInstantApp */,
null /* resolvedType */,
null /* requiredPermissions */,
+ null /* excludedPermissions */,
0 /* appOp */,
null /* options */,
new ArrayList<>(receivers), // Make a copy to not affect the original list.
diff --git a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
index 3231f6204a12..6ca1102b23ef 100644
--- a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
@@ -18,6 +18,8 @@ package com.android.server.am;
import static com.android.server.am.MeasuredEnergySnapshot.UNAVAILABLE;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -224,15 +226,15 @@ public final class MeasuredEnergySnapshotTest {
}
@Test
- public void testGetNumOtherOrdinals() {
+ public void testGetOtherOrdinalNames() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
- assertEquals(3, snapshot.getNumOtherOrdinals());
+ assertThat(snapshot.getOtherOrdinalNames()).asList().containsExactly("GPU", "HPU", "IPU");
}
@Test
- public void testGetNumOtherOrdinals_none() {
+ public void testGetOtherOrdinalNames_none() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(SOME_ID_CONSUMER_MAP);
- assertEquals(0, snapshot.getNumOtherOrdinals());
+ assertEquals(0, snapshot.getOtherOrdinalNames().length);
}
private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index e322ce551372..96bab6119154 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -308,6 +308,8 @@ public class AuthSessionTest {
componentInfo,
type,
false /* resetLockoutRequiresHardwareAuthToken */));
+
+ when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
}
private void setupFace(int id, boolean confirmationAlwaysRequired,
@@ -329,6 +331,6 @@ public class AuthSessionTest {
}
});
- when(mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index a5fbab519aaa..ec3bea33c8db 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -378,7 +378,7 @@ public class BiometricServiceTest {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
// Disabled in user settings receives onError
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
waitForIdle();
@@ -389,7 +389,7 @@ public class BiometricServiceTest {
// Enrolled, not disabled in settings, user requires confirmation in settings
resetReceivers();
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
when(mBiometricService.mSettingObserver.getConfirmationAlwaysRequired(
anyInt() /* modality */, anyInt() /* userId */))
.thenReturn(true);
@@ -1197,7 +1197,7 @@ public class BiometricServiceTest {
@Test
public void testCanAuthenticate_whenBiometricsNotEnabledForApps() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
// When only biometric is requested
@@ -1322,6 +1322,8 @@ public class BiometricServiceTest {
final int testId = 0;
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
+
when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any()))
.thenReturn(true);
when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
@@ -1536,7 +1538,7 @@ public class BiometricServiceTest {
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
if ((modality & BiometricAuthenticator.TYPE_FINGERPRINT) != 0) {
when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any()))
@@ -1564,7 +1566,7 @@ public class BiometricServiceTest {
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
assertEquals(modalities.length, strengths.length);
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 78e2dee7acf8..73ec5b8d3522 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1304,6 +1304,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetDeviceOwner_failures() throws Exception {
// TODO Test more failure cases. Basically test all chacks in enforceCanSetDeviceOwner().
+ // Package doesn't exist and caller is not system
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ "Calling identity is not authorized",
+ () -> dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
+
+ // Package exists, but caller is not system
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ "Calling identity is not authorized",
+ () -> dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
}
@Test
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 39e06a3a362d..950b8a254007 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -25,6 +25,13 @@ import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
@@ -494,4 +501,99 @@ public class HdmiCecLocalDeviceTvTest {
ABORT_UNRECOGNIZED_OPCODE);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort);
}
+
+ @Test
+ public void handleReportAudioStatus_SamOnArcOff_setStreamVolumeNotCalled() {
+ // Emulate Audio device on port 0x1000 (does not support ARC)
+ mNativeWrapper.setPortConnectionStatus(1, true);
+ HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(hdmiCecMessage);
+
+ HdmiCecFeatureAction systemAudioAutoInitiationAction =
+ new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
+ HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ mHdmiControlService.handleCecCommand(reportSystemAudioMode);
+
+ mTestLooper.dispatchAll();
+
+ // SAM must be on; ARC must be off
+ assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
+ assertFalse(mHdmiCecLocalDeviceTv.isArcEstablished());
+
+ HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ 50, // Volume of incoming message does not affect HDMI-CEC logic
+ false);
+ mNativeWrapper.onCecMessage(reportAudioStatus);
+
+ mTestLooper.dispatchAll();
+
+ verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void handleReportAudioStatus_SamOnArcOn_setStreamVolumeCalled() {
+ mNativeWrapper.setPortConnectionStatus(2, true);
+ HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(hdmiCecMessage);
+
+ HdmiCecFeatureAction systemAudioAutoInitiationAction =
+ new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
+
+ HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ mHdmiControlService.handleCecCommand(reportSystemAudioMode);
+
+ HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV);
+ mNativeWrapper.onCecMessage(requestArcInitiation);
+
+ mTestLooper.dispatchAll();
+
+ // SAM and ARC must be on
+ assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
+ assertTrue(mHdmiCecLocalDeviceTv.isArcEstablished());
+
+ HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ 50, // Volume of incoming message does not affect HDMI-CEC logic
+ false);
+ mNativeWrapper.onCecMessage(reportAudioStatus);
+
+ mTestLooper.dispatchAll();
+
+ verify(mAudioManager, times(1)).setStreamVolume(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void handleReportAudioStatus_SamOff_setStreamVolumeNotCalled() {
+ // Emulate Audio device on port 0x1000 (does not support ARC)
+ mNativeWrapper.setPortConnectionStatus(1, true);
+ HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(hdmiCecMessage);
+
+ mTestLooper.dispatchAll();
+
+ assertFalse(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
+
+ HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ 50, // Volume of incoming message does not affect HDMI-CEC logic
+ false);
+ mNativeWrapper.onCecMessage(reportAudioStatus);
+
+ mTestLooper.dispatchAll();
+
+ verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index 691d174f55f8..f2bb1d662ed9 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -87,6 +87,11 @@ public class LockSettingsStorageTestable extends LockSettingsStorage {
}
@Override
+ String getRebootEscrowFile(int userId) {
+ return makeDirs(mStorageDir, super.getRebootEscrowFile(userId)).getAbsolutePath();
+ }
+
+ @Override
protected File getSyntheticPasswordDirectoryForUser(int userId) {
return makeDirs(mStorageDir, super.getSyntheticPasswordDirectoryForUser(
userId).getAbsolutePath());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 8c08226201a8..49a54ec1354b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -21,6 +21,11 @@ import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_PROFILE;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -327,7 +332,7 @@ public class RebootEscrowManagerTests {
assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
assertNotNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
verify(mRebootEscrow).storeKey(any());
@@ -351,7 +356,7 @@ public class RebootEscrowManagerTests {
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -373,7 +378,7 @@ public class RebootEscrowManagerTests {
assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
doThrow(ServiceSpecificException.class).when(mRebootEscrow).storeKey(any());
- assertFalse(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_STORE_ESCROW_KEY, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(any());
}
@@ -396,7 +401,7 @@ public class RebootEscrowManagerTests {
assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
assertNotNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
verify(mRebootEscrow, times(1)).storeKey(any());
@@ -408,15 +413,24 @@ public class RebootEscrowManagerTests {
@Test
public void armService_NoInitialization_Failure() throws Exception {
- assertFalse(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_ESCROW_NOT_READY, mService.armRebootEscrowIfNeeded());
verifyNoMoreInteractions(mRebootEscrow);
}
@Test
public void armService_RebootEscrowServiceException_Failure() throws Exception {
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mRebootEscrow);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mRebootEscrow, never()).storeKey(any());
+
doThrow(RemoteException.class).when(mRebootEscrow).storeKey(any());
- assertFalse(mService.armRebootEscrowIfNeeded());
- verifyNoMoreInteractions(mRebootEscrow);
+ assertEquals(ARM_REBOOT_ERROR_STORE_ESCROW_KEY, mService.armRebootEscrowIfNeeded());
+ verify(mRebootEscrow).storeKey(any());
}
@Test
@@ -439,7 +453,7 @@ public class RebootEscrowManagerTests {
verify(mRebootEscrow, never()).storeKey(any());
ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
verify(mKeyStoreManager).getKeyStoreEncryptionKey();
@@ -483,7 +497,7 @@ public class RebootEscrowManagerTests {
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -520,7 +534,7 @@ public class RebootEscrowManagerTests {
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -557,7 +571,7 @@ public class RebootEscrowManagerTests {
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -597,7 +611,7 @@ public class RebootEscrowManagerTests {
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -635,7 +649,7 @@ public class RebootEscrowManagerTests {
verify(mRebootEscrow, never()).storeKey(any());
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(any());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -695,7 +709,7 @@ public class RebootEscrowManagerTests {
verify(mRebootEscrow, never()).storeKey(any());
ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -732,8 +746,7 @@ public class RebootEscrowManagerTests {
verify(mockListener).onPreparedForReboot(eq(true));
verify(mRebootEscrow, never()).storeKey(any());
-
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(any());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -756,4 +769,28 @@ public class RebootEscrowManagerTests {
assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
metricsErrorCodeCaptor.getValue());
}
+
+ @Test
+ public void armServiceProviderMismatch_Failure() throws Exception {
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mRebootEscrow);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+ verify(mRebootEscrow, never()).storeKey(any());
+
+ assertNull(
+ mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
+ // Change the provider to server based, expect the reboot to fail
+ when(mInjected.forceServerBased()).thenReturn(true);
+ assertEquals(ARM_REBOOT_ERROR_PROVIDER_MISMATCH, mService.armRebootEscrowIfNeeded());
+ assertNull(
+ mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
+ // Verify that the escrow key & data have been cleared.
+ verify(mRebootEscrow).storeKey(eq(new byte[32]));
+ assertFalse(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index 2b358ea5e105..b64810b66542 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -18,11 +18,14 @@ package com.android.server.recoverysystem;
import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME;
import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED;
+import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE;
import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -31,6 +34,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -91,7 +95,8 @@ public class RecoverySystemServiceTest {
mUncryptUpdateFileWriter = mock(FileWriter.class);
mLockSettingsInternal = mock(LockSettingsInternal.class);
- when(mLockSettingsInternal.armRebootEscrow()).thenReturn(true);
+ doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_NONE).when(mLockSettingsInternal)
+ .armRebootEscrow();
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
mIPowerManager = mock(IPowerManager.class);
@@ -489,4 +494,27 @@ public class RecoverySystemServiceTest {
}
// TODO(xunchang) add more multi client tests
+
+ @Test
+ public void rebootWithLskf_armEscrowDataFatalError_Failure() throws Exception {
+ doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH)
+ .when(mLockSettingsInternal).armRebootEscrow();
+
+ assertTrue(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null));
+ mRecoverySystemService.onPreparedForReboot(true);
+ assertTrue(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
+
+ when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
+ + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(1);
+ when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
+ anyInt())).thenReturn(1);
+ assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE,
+ mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true));
+ // Verify that the RoR preparation state has been cleared.
+ assertFalse(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
+ verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(5004 /* provider mismatch */),
+ eq(1000), eq(1) /* client count */, eq(1) /* request count */,
+ eq(true) /* slot switch */, anyBoolean(), anyInt(),
+ eq(1) /* lskf capture count */);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 742f5034a248..32fed3bc3dc1 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -248,21 +248,6 @@ public class TimeDetectorServiceTest {
mStubbedTimeDetectorStrategy.verifyDumpCalled();
}
- @Test
- public void testAutoTimeDetectionToggle() throws Exception {
- mTimeDetectorService.handleAutoTimeDetectionChanged();
- mTestHandler.assertTotalMessagesEnqueued(1);
- mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionChangedCalled();
-
- mStubbedTimeDetectorStrategy.resetCallTracking();
-
- mTimeDetectorService.handleAutoTimeDetectionChanged();
- mTestHandler.assertTotalMessagesEnqueued(2);
- mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionChangedCalled();
- }
-
private static TelephonyTimeSuggestion createTelephonyTimeSuggestion() {
int slotIndex = 1234;
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
@@ -298,7 +283,6 @@ public class TimeDetectorServiceTest {
private NetworkTimeSuggestion mLastNetworkSuggestion;
private GnssTimeSuggestion mLastGnssSuggestion;
private ExternalTimeSuggestion mLastExternalSuggestion;
- private boolean mHandleAutoTimeDetectionChangedCalled;
private boolean mDumpCalled;
@Override
@@ -333,11 +317,6 @@ public class TimeDetectorServiceTest {
}
@Override
- public void handleAutoTimeConfigChanged() {
- mHandleAutoTimeDetectionChangedCalled = true;
- }
-
- @Override
public void dump(IndentingPrintWriter pw, String[] args) {
mDumpCalled = true;
}
@@ -348,7 +327,6 @@ public class TimeDetectorServiceTest {
mLastNetworkSuggestion = null;
mLastGnssSuggestion = null;
mLastExternalSuggestion = null;
- mHandleAutoTimeDetectionChangedCalled = false;
mDumpCalled = false;
}
@@ -372,10 +350,6 @@ public class TimeDetectorServiceTest {
assertEquals(expectedSuggestion, mLastExternalSuggestion);
}
- void verifyHandleAutoTimeDetectionChangedCalled() {
- assertTrue(mHandleAutoTimeDetectionChangedCalled);
- }
-
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 095703e6b939..0d5b5a565d5a 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -37,6 +37,7 @@ import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +47,7 @@ import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
+import java.util.Objects;
@RunWith(AndroidJUnit4.class)
public class TimeDetectorStrategyImplTest {
@@ -1133,11 +1135,17 @@ public class TimeDetectorStrategyImplTest {
private long mSystemClockMillis;
private int mSystemClockUpdateThresholdMillis = 2000;
private int[] mAutoOriginPriorities = PROVIDERS_PRIORITY;
+ private ConfigurationChangeListener mConfigChangeListener;
// Tracking operations.
private boolean mSystemClockWasSet;
@Override
+ public void setConfigChangeListener(ConfigurationChangeListener listener) {
+ mConfigChangeListener = Objects.requireNonNull(listener);
+ }
+
+ @Override
public int systemClockUpdateThresholdMillis() {
return mSystemClockUpdateThresholdMillis;
}
@@ -1230,6 +1238,7 @@ public class TimeDetectorStrategyImplTest {
void simulateAutoTimeZoneDetectionToggle() {
mAutoTimeDetectionEnabled = !mAutoTimeDetectionEnabled;
+ mConfigChangeListener.onChange();
}
void verifySystemClockNotSet() {
@@ -1330,7 +1339,6 @@ public class TimeDetectorStrategyImplTest {
Script simulateAutoTimeDetectionToggle() {
mFakeEnvironment.simulateAutoTimeZoneDetectionToggle();
- mTimeDetectorStrategy.handleAutoTimeConfigChanged();
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java
new file mode 100644
index 000000000000..2f5a5cc97117
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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.uwb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.platform.test.annotations.Presubmit;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.uwb.IUwbAdapter;
+import android.uwb.IUwbAdapterStateCallbacks;
+import android.uwb.IUwbRangingCallbacks;
+import android.uwb.RangingReport;
+import android.uwb.RangingSession;
+import android.uwb.SessionHandle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link UwbServiceImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class UwbServiceImplTest {
+ @Mock private IUwbAdapter mVendorService;
+ @Mock private IBinder mVendorServiceBinder;
+ @Mock private Context mContext;
+ @Mock private UwbInjector mUwbInjector;
+ @Captor private ArgumentCaptor<IUwbRangingCallbacks> mRangingCbCaptor;
+ @Captor private ArgumentCaptor<IBinder.DeathRecipient> mClientDeathCaptor;
+ @Captor private ArgumentCaptor<IBinder.DeathRecipient> mVendorServiceDeathCaptor;
+
+ private UwbServiceImpl mUwbServiceImpl;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mUwbInjector.getVendorService()).thenReturn(mVendorService);
+ when(mVendorService.asBinder()).thenReturn(mVendorServiceBinder);
+ mUwbServiceImpl = new UwbServiceImpl(mContext, mUwbInjector);
+ }
+
+ @Test
+ public void testApiCallThrowsIllegalStateExceptionIfVendorServiceNotFound() throws Exception {
+ when(mUwbInjector.getVendorService()).thenReturn(null);
+
+ final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
+ try {
+ mUwbServiceImpl.registerAdapterStateCallbacks(cb);
+ fail();
+ } catch (IllegalStateException e) { /* pass */ }
+ }
+
+ @Test
+ public void testRegisterAdapterStateCallbacks() throws Exception {
+ final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
+ mUwbServiceImpl.registerAdapterStateCallbacks(cb);
+
+ verify(mVendorService).registerAdapterStateCallbacks(cb);
+ }
+
+ @Test
+ public void testUnregisterAdapterStateCallbacks() throws Exception {
+ final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
+ mUwbServiceImpl.unregisterAdapterStateCallbacks(cb);
+
+ verify(mVendorService).unregisterAdapterStateCallbacks(cb);
+ }
+
+ @Test
+ public void testGetTimestampResolutionNanos() throws Exception {
+ final long timestamp = 34L;
+ when(mVendorService.getTimestampResolutionNanos()).thenReturn(timestamp);
+ assertThat(mUwbServiceImpl.getTimestampResolutionNanos()).isEqualTo(timestamp);
+
+ verify(mVendorService).getTimestampResolutionNanos();
+ }
+
+ @Test
+ public void testGetSpecificationInfo() throws Exception {
+ final PersistableBundle specification = new PersistableBundle();
+ when(mVendorService.getSpecificationInfo()).thenReturn(specification);
+ assertThat(mUwbServiceImpl.getSpecificationInfo()).isEqualTo(specification);
+
+ verify(mVendorService).getSpecificationInfo();
+ }
+
+ @Test
+ public void testOpenRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+ }
+
+ @Test
+ public void testStartRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final PersistableBundle parameters = new PersistableBundle();
+
+ mUwbServiceImpl.startRanging(sessionHandle, parameters);
+
+ verify(mVendorService).startRanging(sessionHandle, parameters);
+ }
+
+ @Test
+ public void testReconfigureRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final PersistableBundle parameters = new PersistableBundle();
+
+ mUwbServiceImpl.reconfigureRanging(sessionHandle, parameters);
+
+ verify(mVendorService).reconfigureRanging(sessionHandle, parameters);
+ }
+
+ @Test
+ public void testStopRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+
+ mUwbServiceImpl.stopRanging(sessionHandle);
+
+ verify(mVendorService).stopRanging(sessionHandle);
+ }
+
+ @Test
+ public void testCloseRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+
+ mUwbServiceImpl.closeRanging(sessionHandle);
+
+ verify(mVendorService).closeRanging(sessionHandle);
+ }
+
+ @Test
+ public void testRangingCallbacks() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+
+ // Invoke vendor service callbacks and ensure that the corresponding app callback is
+ // invoked.
+ mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
+ verify(cb).onRangingOpened(sessionHandle);
+
+ mRangingCbCaptor.getValue().onRangingOpenFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingOpenFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters);
+ verify(cb).onRangingStarted(sessionHandle, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStartFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingStartFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingReconfigured(sessionHandle, parameters);
+ verify(cb).onRangingReconfigured(sessionHandle, parameters);
+
+ mRangingCbCaptor.getValue().onRangingReconfigureFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingReconfigureFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStopped(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingStopped(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStopFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingStopFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ final RangingReport rangingReport = new RangingReport.Builder().build();
+ mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport);
+ verify(cb).onRangingResult(sessionHandle, rangingReport);
+
+ mRangingCbCaptor.getValue().onRangingClosed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingClosed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ }
+
+ @Test
+ public void testHandleClientDeath() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+
+ verify(cbBinder).linkToDeath(mClientDeathCaptor.capture(), anyInt());
+ assertThat(mClientDeathCaptor.getValue()).isNotNull();
+
+ clearInvocations(cb);
+
+ // Invoke cb, ensure it reaches the client.
+ mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
+ verify(cb).onRangingOpened(sessionHandle);
+
+ // Trigger client death and ensure the session is stopped.
+ mClientDeathCaptor.getValue().binderDied();
+ verify(mVendorService).stopRanging(sessionHandle);
+ verify(mVendorService).closeRanging(sessionHandle);
+
+ // Invoke cb, it should be ignored.
+ mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters);
+ verify(cb, never()).onRangingStarted(any(), any());
+ }
+
+ @Test
+ public void testHandleVendorServiceDeath() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorServiceBinder).linkToDeath(mVendorServiceDeathCaptor.capture(), anyInt());
+ assertThat(mVendorServiceDeathCaptor.getValue()).isNotNull();
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+
+ clearInvocations(cb);
+
+ // Invoke cb, ensure it reaches the client.
+ mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
+ verify(cb).onRangingOpened(sessionHandle);
+
+ // Trigger vendor service death and ensure that the client is informed of session end.
+ mVendorServiceDeathCaptor.getValue().binderDied();
+ verify(cb).onRangingClosed(
+ eq(sessionHandle), eq(RangingSession.Callback.REASON_UNKNOWN),
+ argThat((p) -> p.isEmpty()));
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 678defe36566..57cf865268ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -23,17 +23,27 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doCallRealMethod;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
import androidx.test.filters.FlakyTest;
@@ -426,4 +436,104 @@ public class AppTransitionControllerTest extends WindowTestsBase {
AppTransitionController.getAnimationTargets(
opening, closing, false /* visible */));
}
-}
+
+ static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
+ @Override
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ }
+
+ @Override
+ public void onAnimationCancelled() throws RemoteException {
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return new Binder();
+ }
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideEmpty() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ assertNull(mAppTransitionController.getRemoteAnimationOverride(activity,
+ TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideWindowContainer() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
+ activity.registerRemoteAnimations(definition);
+
+ assertEquals(adapter,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ assertNull(mAppTransitionController.getRemoteAnimationOverride(
+ null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideTransitionController() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
+ mAppTransitionController.registerRemoteAnimations(definition);
+
+ assertEquals(adapter,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ assertEquals(adapter,
+ mAppTransitionController.getRemoteAnimationOverride(
+ null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideBoth() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1);
+ activity.registerRemoteAnimations(definition1);
+
+ final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition2.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, adapter2);
+ mAppTransitionController.registerRemoteAnimations(definition2);
+
+ assertEquals(adapter2,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>()));
+ assertEquals(adapter2,
+ mAppTransitionController.getRemoteAnimationOverride(
+ null, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideWindowContainerHasPriority() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1);
+ activity.registerRemoteAnimations(definition1);
+
+ final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition2.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter2);
+ mAppTransitionController.registerRemoteAnimations(definition2);
+
+ assertEquals(adapter1,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+} \ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index afaf1b1fea0a..491fe98660c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -110,6 +110,7 @@ public class SystemServicesTestRule implements TestRule {
private ActivityTaskManagerService mAtmService;
private WindowManagerService mWmService;
private TestWindowManagerPolicy mWMPolicy;
+ private TestDisplayWindowSettingsProvider mTestDisplayWindowSettingsProvider;
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
@@ -284,10 +285,12 @@ public class SystemServicesTestRule implements TestRule {
mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
mWMPolicy = new TestWindowManagerPolicy(this::getWindowManagerService,
mPowerManagerWrapper);
+ mTestDisplayWindowSettingsProvider = new TestDisplayWindowSettingsProvider();
// Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
mWmService = WindowManagerService.main(
- mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new,
+ mContext, mImService, false, false, mWMPolicy, mAtmService,
+ mTestDisplayWindowSettingsProvider, StubTransaction::new,
() -> mSurfaceFactory.get(), (unused) -> new MockSurfaceControlBuilder());
spyOn(mWmService);
spyOn(mWmService.mRoot);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index 777149b60098..ce2d74859931 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -147,10 +147,6 @@ class TestDisplayContent extends DisplayContent {
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
final TestDisplayContent newDisplay = createInternal(display);
- // Ensure letterbox aspect ratio is not overridden on any device target.
- // {@link com.android.internal.R.dimen.config_taskLetterboxAspectRatio}, provided by
- // the below method, is set on some device form factors.
- mService.mWindowManager.setFixedOrientationLetterboxAspectRatio(0);
// disable the normal system decorations
final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy();
spyOn(displayPolicy);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
new file mode 100644
index 000000000000..b2e44b1421f4
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+import android.view.DisplayInfo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * In-memory DisplayWindowSettingsProvider used in tests. Ensures no settings are read from or
+ * written to device-specific display settings files.
+ */
+public final class TestDisplayWindowSettingsProvider extends DisplayWindowSettingsProvider {
+
+ private final Map<String, SettingsEntry> mOverrideSettingsMap = new HashMap<>();
+
+ @Override
+ @NonNull
+ public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+ // Because no settings are read from settings files, there is no need to store base
+ // settings. Only override settings are necessary to track because they can be modified
+ // during tests (e.g. display size, ignore orientation requests).
+ return getOverrideSettings(info);
+ }
+
+ @Override
+ @NonNull
+ public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+ return new SettingsEntry(getOrCreateOverrideSettingsEntry(info));
+ }
+
+ @Override
+ public void updateOverrideSettings(@NonNull DisplayInfo info,
+ @NonNull SettingsEntry overrides) {
+ final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+ overrideSettings.setTo(overrides);
+ }
+
+ @NonNull
+ private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info);
+ SettingsEntry settings;
+ if ((settings = mOverrideSettingsMap.get(identifier)) != null) {
+ return settings;
+ }
+ settings = new SettingsEntry();
+ mOverrideSettingsMap.put(identifier, settings);
+ return settings;
+ }
+
+ /**
+ * In {@link TestDisplayWindowSettingsProvider}, always use uniqueId as the identifier.
+ */
+ private static String getIdentifier(DisplayInfo displayInfo) {
+ return displayInfo.uniqueId;
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index ae8e2ded359d..acadb74d333f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -210,7 +210,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public boolean okToAnimate() {
+ public boolean okToAnimate(boolean ignoreScreenOn) {
return mOkToAnimate;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index dd0c9e6d390e..d9aa871447be 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -50,7 +51,13 @@ import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.view.IWindowSessionCallback;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.View;
+import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -250,4 +257,31 @@ public class WindowManagerServiceTests extends WindowTestsBase {
eq(clientToken), eq(windowToken), anyInt(), eq(TYPE_INPUT_METHOD),
eq(windowToken.mOptions));
}
+
+ @Test
+ public void testAddWindowWithSubWindowTypeByWindowContext() {
+ spyOn(mWm.mWindowContextListenerController);
+
+ final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay);
+ final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float v) throws RemoteException {}
+ });
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ TYPE_APPLICATION_ATTACHED_DIALOG);
+ params.token = windowToken.token;
+ final IBinder windowContextToken = new Binder();
+ params.setWindowContextToken(windowContextToken);
+ doReturn(true).when(mWm.mWindowContextListenerController)
+ .hasListener(eq(windowContextToken));
+ doReturn(TYPE_INPUT_METHOD).when(mWm.mWindowContextListenerController)
+ .getWindowType(eq(windowContextToken));
+
+ mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY,
+ UserHandle.USER_SYSTEM, new InsetsState(), null, new InsetsState(),
+ new InsetsSourceControl[0]);
+
+ verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(),
+ any(), anyInt(), anyInt(), any());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 39fdb2d48a70..5bafbbd2bdf7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -55,6 +55,8 @@ import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
@@ -153,6 +155,22 @@ class WindowTestsBase extends SystemServiceTestsBase {
*/
Transaction mTransaction;
+ /**
+ * Whether device-specific global overrides have already been checked in
+ * {@link WindowTestsBase#setUpBase()}.
+ */
+ private static boolean sGlobalOverridesChecked;
+ /**
+ * Whether device-specific overrides have already been checked in
+ * {@link WindowTestsBase#setUpBase()} when the default display is used.
+ */
+ private static boolean sOverridesCheckedDefaultDisplay;
+ /**
+ * Whether device-specific overrides have already been checked in
+ * {@link WindowTestsBase#setUpBase()} when a {@link TestDisplayContent} is used.
+ */
+ private static boolean sOverridesCheckedTestDisplay;
+
@BeforeClass
public static void setUpOnceBase() {
AttributeCache.init(getInstrumentation().getTargetContext());
@@ -190,6 +208,28 @@ class WindowTestsBase extends SystemServiceTestsBase {
// {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set
// on some device form factors.
mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio(0);
+
+ checkDeviceSpecificOverridesNotApplied();
+ }
+
+ /**
+ * Check that device-specific overrides are not applied. Only need to check once during entire
+ * test run for each case: global overrides, default display, and test display.
+ */
+ private void checkDeviceSpecificOverridesNotApplied() {
+ // Check global overrides
+ if (!sGlobalOverridesChecked) {
+ assertEquals(0, mWm.getFixedOrientationLetterboxAspectRatio(), 0 /* delta */);
+ sGlobalOverridesChecked = true;
+ }
+ // Check display-specific overrides
+ if (!sOverridesCheckedDefaultDisplay && mDisplayContent == mDefaultDisplay) {
+ assertFalse(mDisplayContent.getIgnoreOrientationRequest());
+ sOverridesCheckedDefaultDisplay = true;
+ } else if (!sOverridesCheckedTestDisplay && mDisplayContent instanceof TestDisplayContent) {
+ assertFalse(mDisplayContent.getIgnoreOrientationRequest());
+ sOverridesCheckedTestDisplay = true;
+ }
}
private void createTestDisplay(UseTestDisplay annotation) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a6b68e1e2ab2..309673d72dd4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -24,6 +24,7 @@ import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
import static android.app.usage.UsageEvents.Event.LOCUS_ID_SET;
import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION;
import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION;
+import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
import static android.app.usage.UsageEvents.Event.USER_STOPPED;
import static android.app.usage.UsageEvents.Event.USER_UNLOCKED;
import static android.app.usage.UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
@@ -112,6 +113,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
@@ -1988,6 +1990,17 @@ public class UsageStatsService extends SystemService implements
}
@Override
+ public void reportUserInteraction(String packageName, int userId) {
+ Objects.requireNonNull(packageName);
+ if (!isCallingUidSystem()) {
+ throw new SecurityException("Only system is allowed to call reportUserInteraction");
+ }
+ final Event event = new Event(USER_INTERACTION, SystemClock.elapsedRealtime());
+ event.mPackage = packageName;
+ reportEventOrAddToQueue(userId, event);
+ }
+
+ @Override
public void registerAppUsageObserver(int observerId,
String[] packages, long timeLimitMs, PendingIntent
callbackIntent, String callingPackage) {
diff --git a/services/uwb/Android.bp b/services/uwb/Android.bp
new file mode 100644
index 000000000000..da30d43a4536
--- /dev/null
+++ b/services/uwb/Android.bp
@@ -0,0 +1,26 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "services.uwb-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+ name: "services.uwb",
+ defaults: ["platform_service_defaults"],
+ srcs: [
+ ":services.uwb-sources",
+ ],
+ libs: [
+ "services.core",
+ ],
+}
diff --git a/services/uwb/java/com/android/server/uwb/UwbInjector.java b/services/uwb/java/com/android/server/uwb/UwbInjector.java
new file mode 100644
index 000000000000..00c0acabcb3b
--- /dev/null
+++ b/services/uwb/java/com/android/server/uwb/UwbInjector.java
@@ -0,0 +1,48 @@
+/*
+ * 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.uwb;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.uwb.IUwbAdapter;
+
+
+/**
+ * To be used for dependency injection (especially helps mocking static dependencies).
+ */
+public class UwbInjector {
+ private static final String TAG = "UwbInjector";
+
+ private static final String VENDOR_SERVICE_NAME = "uwb_vendor";
+
+ private final Context mContext;
+
+ public UwbInjector(@NonNull Context context) {
+ mContext = context;
+ }
+
+ /**
+ * @return Returns the vendor service handle.
+ */
+ public IUwbAdapter getVendorService() {
+ IBinder b = ServiceManager.getService(VENDOR_SERVICE_NAME);
+ if (b == null) return null;
+ return IUwbAdapter.Stub.asInterface(b);
+ }
+}
diff --git a/services/uwb/java/com/android/server/uwb/UwbService.java b/services/uwb/java/com/android/server/uwb/UwbService.java
new file mode 100644
index 000000000000..4bb280f75ed1
--- /dev/null
+++ b/services/uwb/java/com/android/server/uwb/UwbService.java
@@ -0,0 +1,42 @@
+/*
+ * 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.uwb;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+/**
+ * Uwb System service.
+ */
+public class UwbService extends SystemService {
+ private static final String TAG = "UwbService";
+
+ private final UwbServiceImpl mImpl;
+
+ public UwbService(Context context) {
+ super(context);
+ mImpl = new UwbServiceImpl(context, new UwbInjector(context));
+ }
+
+ @Override
+ public void onStart() {
+ Log.i(TAG, "Registering " + Context.UWB_SERVICE);
+ publishBinderService(Context.UWB_SERVICE, mImpl);
+ }
+}
diff --git a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
new file mode 100644
index 000000000000..70bd20e0014e
--- /dev/null
+++ b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
@@ -0,0 +1,288 @@
+/*
+ * 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.uwb;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.uwb.IUwbAdapter;
+import android.uwb.IUwbAdapterStateCallbacks;
+import android.uwb.IUwbRangingCallbacks;
+import android.uwb.RangingReport;
+import android.uwb.RangingSession;
+import android.uwb.SessionHandle;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Map;
+
+/**
+ * Implementation of {@link android.uwb.IUwbAdapter} binder service.
+ */
+public class UwbServiceImpl extends IUwbAdapter.Stub implements IBinder.DeathRecipient{
+ private static final String TAG = "UwbServiceImpl";
+
+ private final Context mContext;
+ private final UwbInjector mUwbInjector;
+ /**
+ * Map for storing the callbacks wrapper for each session.
+ */
+ @GuardedBy("mCallbacksMap")
+ private final Map<SessionHandle, UwbRangingCallbacksWrapper> mCallbacksMap = new ArrayMap<>();
+
+ /**
+ * Used for caching the vendor implementation of {@link IUwbAdapter} interface.
+ */
+ private IUwbAdapter mVendorUwbAdapter;
+
+ /**
+ * Wrapper for callback registered with vendor service. This wrapper is needed for performing
+ * permission check before sending the callback to the external app.
+ *
+ * Access to these callbacks are synchronized.
+ */
+ private class UwbRangingCallbacksWrapper extends IUwbRangingCallbacks.Stub
+ implements IBinder.DeathRecipient{
+ private final SessionHandle mSessionHandle;
+ private final IUwbRangingCallbacks mExternalCb;
+ private boolean mIsValid;
+
+ UwbRangingCallbacksWrapper(@NonNull SessionHandle sessionHandle,
+ @NonNull IUwbRangingCallbacks externalCb) {
+ mSessionHandle = sessionHandle;
+ mExternalCb = externalCb;
+ mIsValid = true;
+
+ // Link to death for external callback.
+ linkToDeath();
+ }
+
+ private void linkToDeath() {
+ IBinder binder = mExternalCb.asBinder();
+ try {
+ binder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to link to client death event.", e);
+ }
+ }
+
+ private void removeClientAndUnlinkToDeath() {
+ // Remove from the map.
+ synchronized (mCallbacksMap) {
+ mCallbacksMap.remove(mSessionHandle);
+ }
+ IBinder binder = mExternalCb.asBinder();
+ binder.unlinkToDeath(this, 0);
+ mIsValid = false;
+ }
+
+
+ @Override
+ public synchronized void onRangingOpened(SessionHandle sessionHandle)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingOpened(sessionHandle);
+ }
+
+ @Override
+ public synchronized void onRangingOpenFailed(SessionHandle sessionHandle,
+ int reason, PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingOpenFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStarted(SessionHandle sessionHandle,
+ PersistableBundle parameters)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStarted(sessionHandle, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStartFailed(SessionHandle sessionHandle,
+ int reason, PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStartFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingReconfigured(SessionHandle sessionHandle,
+ PersistableBundle parameters)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingReconfigured(sessionHandle, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingReconfigureFailed(SessionHandle sessionHandle,
+ int reason, PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingReconfigureFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStopped(SessionHandle sessionHandle, int reason,
+ PersistableBundle parameters)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStopped(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStopFailed(SessionHandle sessionHandle, int reason,
+ PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStopFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingClosed(SessionHandle sessionHandle, int reason,
+ PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingClosed(sessionHandle, reason, parameters);
+ removeClientAndUnlinkToDeath();
+ }
+
+ @Override
+ public synchronized void onRangingResult(SessionHandle sessionHandle,
+ RangingReport rangingReport)
+ throws RemoteException {
+ if (!mIsValid) return;
+ // TODO: Perform permission checks and noteOp.
+ mExternalCb.onRangingResult(sessionHandle, rangingReport);
+ }
+
+ @Override
+ public synchronized void binderDied() {
+ if (!mIsValid) return;
+ Log.i(TAG, "Client died: ending session: " + mSessionHandle);
+ try {
+ removeClientAndUnlinkToDeath();
+ stopRanging(mSessionHandle);
+ closeRanging(mSessionHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote exception while handling client death", e);
+ }
+ }
+ }
+
+ private void linkToVendorServiceDeath() {
+ IBinder binder = mVendorUwbAdapter.asBinder();
+ try {
+ binder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to link to vendor service death event.", e);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ Log.i(TAG, "Vendor service died: sending session close callbacks");
+ synchronized (mCallbacksMap) {
+ for (Map.Entry<SessionHandle, UwbRangingCallbacksWrapper> e : mCallbacksMap.entrySet()) {
+ try {
+ e.getValue().mExternalCb.onRangingClosed(
+ e.getKey(), RangingSession.Callback.REASON_UNKNOWN,
+ new PersistableBundle());
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to send session close callback " + e.getKey(), ex);
+ }
+ }
+ // Clear all sessions.
+ mCallbacksMap.clear();
+ }
+ mVendorUwbAdapter = null;
+ }
+
+ private synchronized IUwbAdapter getVendorUwbAdapter() throws IllegalStateException {
+ if (mVendorUwbAdapter != null) return mVendorUwbAdapter;
+ mVendorUwbAdapter = mUwbInjector.getVendorService();
+ if (mVendorUwbAdapter == null) {
+ throw new IllegalStateException("No vendor service found!");
+ }
+ Log.i(TAG, "Retrieved vendor service");
+ linkToVendorServiceDeath();
+ return mVendorUwbAdapter;
+ }
+
+ UwbServiceImpl(@NonNull Context context, @NonNull UwbInjector uwbInjector) {
+ mContext = context;
+ mUwbInjector = uwbInjector;
+ }
+
+ @Override
+ public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
+ throws RemoteException {
+ getVendorUwbAdapter().registerAdapterStateCallbacks(adapterStateCallbacks);
+ }
+
+ @Override
+ public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
+ throws RemoteException {
+ getVendorUwbAdapter().unregisterAdapterStateCallbacks(adapterStateCallbacks);
+ }
+
+ @Override
+ public long getTimestampResolutionNanos() throws RemoteException {
+ return getVendorUwbAdapter().getTimestampResolutionNanos();
+ }
+
+ @Override
+ public PersistableBundle getSpecificationInfo() throws RemoteException {
+ return getVendorUwbAdapter().getSpecificationInfo();
+ }
+
+ @Override
+ public void openRanging(SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks,
+ PersistableBundle parameters) throws RemoteException {
+ UwbRangingCallbacksWrapper wrapperCb =
+ new UwbRangingCallbacksWrapper(sessionHandle, rangingCallbacks);
+ synchronized (mCallbacksMap) {
+ mCallbacksMap.put(sessionHandle, wrapperCb);
+ }
+ getVendorUwbAdapter().openRanging(sessionHandle, wrapperCb, parameters);
+ }
+
+ @Override
+ public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters)
+ throws RemoteException {
+ // TODO: Perform permission checks.
+ getVendorUwbAdapter().startRanging(sessionHandle, parameters);
+ }
+
+ @Override
+ public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters)
+ throws RemoteException {
+ getVendorUwbAdapter().reconfigureRanging(sessionHandle, parameters);
+ }
+
+ @Override
+ public void stopRanging(SessionHandle sessionHandle) throws RemoteException {
+ getVendorUwbAdapter().stopRanging(sessionHandle);
+ }
+
+ @Override
+ public void closeRanging(SessionHandle sessionHandle) throws RemoteException {
+ getVendorUwbAdapter().closeRanging(sessionHandle);
+ }
+
+}
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index f6d18fcd9ab3..96e715ee0495 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -637,18 +637,18 @@ public final class AccessNetworkConstants {
this.band = band;
this.downlinkLowKhz = downlinkLowKhz;
this.downlinkOffset = downlinkOffset;
+ this.downlinkRange = downlinkRange;
this.uplinkLowKhz = uplinkLowKhz;
this.uplinkOffset = uplinkOffset;
- this.downlinkRange = downlinkRange;
this.uplinkRange = uplinkRange;
}
int band;
int downlinkLowKhz;
int downlinkOffset;
+ int downlinkRange;
int uplinkLowKhz;
int uplinkOffset;
- int downlinkRange;
int uplinkRange;
}
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index f29f3bd352be..6b820459be98 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -598,7 +598,8 @@ public class AccessNetworkUtils {
: earfcnFrequency.downlinkOffset;
break;
} else {
- Log.e(TAG, "Band and the range of EARFCN are not consistent.");
+ Rlog.w(TAG,"Band and the range of EARFCN are not consistent: band = " + band
+ + " ,earfcn = " + earfcn + " ,isUplink = " + isUplink);
return INVALID_FREQUENCY;
}
}
@@ -617,7 +618,7 @@ public class AccessNetworkUtils {
}
private static boolean isInEarfcnRange(int earfcn, EutranBandArfcnFrequency earfcnFrequency,
- boolean isUplink) {
+ boolean isUplink) {
if (isUplink) {
return earfcn >= earfcnFrequency.uplinkOffset && earfcn <= earfcnFrequency.uplinkRange;
} else {
@@ -640,7 +641,8 @@ public class AccessNetworkUtils {
: uarfcnFrequency.downlinkOffset;
break;
} else {
- Log.e(TAG, "Band and the range of UARFCN are not consistent.");
+ Rlog.w(TAG,"Band and the range of UARFCN are not consistent: band = " + band
+ + " ,uarfcn = " + uarfcn + " ,isUplink = " + isUplink);
return INVALID_FREQUENCY;
}
}
@@ -716,7 +718,8 @@ public class AccessNetworkUtils {
arfcnOffset);
break;
} else {
- Log.e(TAG, "Band and the range of ARFCN are not consistent.");
+ Rlog.w(TAG,"Band and the range of ARFCN are not consistent: band = " + band
+ + " ,arfcn = " + arfcn + " ,isUplink = " + isUplink);
return INVALID_FREQUENCY;
}
}
@@ -733,7 +736,7 @@ public class AccessNetworkUtils {
* Downlink actual frequency(kHz) = Uplink actual frequency + 10
*/
private static int convertArfcnToFrequency(int arfcn, int uplinkFrequencyFirstKhz,
- int arfcnOffset) {
+ int arfcnOffset) {
return uplinkFrequencyFirstKhz + 200 * (arfcn - arfcnOffset);
}
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index d21fcab264d3..391372ac8ac1 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -203,23 +203,6 @@ public final class SipMessage implements Parcelable {
}
/**
- * @return the UTF-8 encoded SIP message.
- * @deprecated Use {@link #toEncodedMessage} instead
- */
- @Deprecated
- public @NonNull byte[] getEncodedMessage() {
- byte[] header = new StringBuilder()
- .append(mStartLine)
- .append(mHeaderSection)
- .append(CRLF)
- .toString().getBytes(UTF_8);
- byte[] sipMessage = new byte[header.length + mContent.length];
- System.arraycopy(header, 0, sipMessage, 0, header.length);
- System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
- return sipMessage;
- }
-
- /**
* According RFC-3261 section 7, SIP is a text protocol and uses the UTF-8 charset. Its format
* consists of a start-line, one or more header fields, an empty line indicating the end of the
* header fields, and an optional message-body.
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
index ec859955694c..2d230a74a477 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
@@ -23,6 +23,7 @@ import android.app.blob.BlobStoreManager;
import android.app.blob.LeaseInfo;
import android.content.Context;
import android.content.res.Resources;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -56,6 +57,16 @@ public class Utils {
}
}
+ public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input)
+ throws IOException {
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
+ try (FileOutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
+ session.openWrite(0, -1))) {
+ FileUtils.copy(in, out);
+ }
+ }
+ }
+
public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input,
long lengthBytes) throws IOException {
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index ed0a98d3c1ec..059361525733 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -19,19 +19,21 @@ package com.android.server.wm.flicker
import android.platform.helpers.IAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_WINDOW_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
-const val WALLPAPER_TITLE = "Wallpaper"
+val LAUNCHER_TITLE = arrayOf("Wallpaper", "Launcher", "com.google.android.googlequicksearchbox")
fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
assertWm {
- this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
+ this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME)
}
}
fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
assertWm {
- this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
+ this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME)
}
}
@@ -39,23 +41,23 @@ fun FlickerTestParameter.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelpe
assertWm {
this.showsAppWindowOnTop(testApp.getPackage())
.then()
- .showsAppWindowOnTop("Launcher")
+ .showsAppWindowOnTop(*LAUNCHER_TITLE)
}
}
-fun FlickerTestParameter.wallpaperWindowBecomesVisible() {
+fun FlickerTestParameter.launcherWindowBecomesVisible() {
assertWm {
- this.hidesBelowAppWindow(WALLPAPER_TITLE)
+ this.hidesBelowAppWindow(*LAUNCHER_TITLE)
.then()
- .showsBelowAppWindow(WALLPAPER_TITLE)
+ .showsBelowAppWindow(*LAUNCHER_TITLE)
}
}
-fun FlickerTestParameter.wallpaperWindowBecomesInvisible() {
+fun FlickerTestParameter.launcherWindowBecomesInvisible() {
assertWm {
- this.showsBelowAppWindow(WALLPAPER_TITLE)
+ this.showsBelowAppWindow(*LAUNCHER_TITLE)
.then()
- .hidesBelowAppWindow(WALLPAPER_TITLE)
+ .hidesBelowAppWindow(*LAUNCHER_TITLE)
}
}
@@ -130,15 +132,15 @@ fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = fal
fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
if (rotatesScreen) {
assertLayers {
- this.isVisible(STATUS_BAR_WINDOW_NAME)
+ this.isVisible(STATUS_BAR_LAYER_NAME)
.then()
- .isInvisible(STATUS_BAR_WINDOW_NAME)
+ .isInvisible(STATUS_BAR_LAYER_NAME)
.then()
- .isVisible(STATUS_BAR_WINDOW_NAME)
+ .isVisible(STATUS_BAR_LAYER_NAME)
}
} else {
assertLayers {
- this.isVisible(STATUS_BAR_WINDOW_NAME)
+ this.isVisible(STATUS_BAR_LAYER_NAME)
}
}
}
@@ -168,34 +170,27 @@ fun FlickerTestParameter.statusBarLayerRotatesScales(
val endingPos = WindowUtils.getStatusBarPosition(endRotation)
assertLayersStart {
- this.visibleRegion(STATUS_BAR_WINDOW_NAME).coversExactly(startingPos)
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(startingPos)
}
assertLayersEnd {
- this.visibleRegion(STATUS_BAR_WINDOW_NAME).coversExactly(endingPos)
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(endingPos)
}
}
-fun FlickerTestParameter.appLayerReplacesWallpaperLayer(appName: String) {
+fun FlickerTestParameter.appLayerReplacesLauncher(appName: String) {
assertLayers {
- this.isVisible(WALLPAPER_TITLE)
+ this.isVisible(*LAUNCHER_TITLE)
.then()
- .isInvisible(WALLPAPER_TITLE)
.isVisible(appName)
}
}
-fun FlickerTestParameter.wallpaperLayerReplacesAppLayer(testApp: IAppHelper) {
+fun FlickerTestParameter.launcherLayerReplacesApp(testApp: IAppHelper) {
assertLayers {
this.isVisible(testApp.getPackage())
.then()
.isInvisible(testApp.getPackage())
- .isVisible(WALLPAPER_TITLE)
- }
-}
-
-fun FlickerTestParameter.layerAlwaysVisible(packageName: String) {
- assertLayers {
- this.isVisible(packageName)
+ .isVisible(*LAUNCHER_TITLE)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index c92d40cdd555..db91eb21d532 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,12 +16,14 @@
package com.android.server.wm.flicker.close
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -44,6 +46,30 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
}
}
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun launcherLayerReplacesApp() {
+ super.launcherLayerReplacesApp()
+ }
+
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun launcherReplacesAppWindowAsTopWindow() {
+ super.launcherReplacesAppWindowAsTopWindow()
+ }
+
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun launcherWindowBecomesVisible() {
+ super.launcherWindowBecomesVisible()
+ }
+
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index a524466328f5..9ac504ba3e6f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -36,8 +36,8 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
-import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
+import com.android.server.wm.flicker.launcherLayerReplacesApp
+import com.android.server.wm.flicker.launcherWindowBecomesVisible
import org.junit.Test
abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
@@ -76,16 +76,16 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
testSpec.statusBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible()
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible()
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
@FlakyTest
@@ -130,13 +130,13 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
@Presubmit
@Test
- open fun wallpaperWindowBecomesVisible() {
- testSpec.wallpaperWindowBecomesVisible()
+ open fun launcherWindowBecomesVisible() {
+ testSpec.launcherWindowBecomesVisible()
}
@Presubmit
@Test
- open fun wallpaperLayerReplacesAppLayer() {
- testSpec.wallpaperLayerReplacesAppLayer(testApp)
+ open fun launcherLayerReplacesApp() {
+ testSpec.launcherLayerReplacesApp(testApp)
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 90c23385d16b..3bd19ea74f1d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -18,6 +18,7 @@ package com.android.server.wm.flicker.ime
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -50,6 +51,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 185400889)
class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
@@ -64,7 +66,7 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
}
}
teardown {
- test {
+ eachRun {
testApp.exit(wmHelper)
}
}
@@ -104,7 +106,7 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
@@ -141,7 +143,10 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 5,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index dfb229d54c99..3cb58b9b25d6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -19,6 +19,7 @@ package com.android.server.wm.flicker.ime
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -65,7 +66,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
}
}
teardown {
- test {
+ eachRun {
testApp.exit(wmHelper)
}
}
@@ -95,24 +96,24 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
}
}
- @Presubmit
+ @FlakyTest
@Test
fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
- @Presubmit
+ @FlakyTest
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
Surface.ROTATION_0)
- @Presubmit
+ @FlakyTest
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
@@ -132,7 +133,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
@@ -150,7 +151,10 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 1,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 6b8bf63aa926..cdec51d25d7f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -76,11 +76,11 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
}
}
- @Presubmit
+ @FlakyTest
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
@@ -106,7 +106,7 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
@@ -138,7 +138,7 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
}
- @Presubmit
+ @FlakyTest
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 9b37cafa74c3..22d341866088 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -20,6 +20,7 @@ import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -97,11 +98,11 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
}
}
- @Presubmit
+ @FlakyTest
@Test
fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 7ba9db19dd52..bb9cd6fef4a2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -34,7 +34,6 @@ import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
@@ -113,7 +112,11 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`)
+ fun layerAlwaysVisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.`package`)
+ }
+ }
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index be0357e826a8..55bbe3aa2b5c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -33,8 +33,8 @@ import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesLauncher
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
@@ -107,7 +107,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
+ fun launcherWindowBecomesInvisible() = testSpec.launcherWindowBecomesInvisible()
@Presubmit
@Test
@@ -138,8 +138,8 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun appLayerReplacesWallpaperLayer() =
- testSpec.appLayerReplacesWallpaperLayer(testAppComponentName.className)
+ fun appLayerReplacesLauncher() =
+ testSpec.appLayerReplacesLauncher(testAppComponentName.className)
@FlakyTest
@Test
@@ -168,9 +168,9 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
repetitions = 1,
+ supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
- WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY
)
)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 8e73ab18fc95..d0e95566f1b5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -19,6 +19,7 @@ package com.android.server.wm.flicker.ime
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -51,6 +52,7 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest
class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = SimpleAppHelper(instrumentation)
@@ -131,7 +133,7 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
.getConfigNonRotationTests(
repetitions = 3,
supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
)
)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index 130860d31ac1..6a7309c4c120 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -18,10 +18,11 @@ package com.android.server.wm.flicker.launch
import android.platform.helpers.IAppHelper
import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.LAUNCHER_TITLE
fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) {
assertWm {
- this.showsAppWindowOnTop("Launcher")
+ this.showsAppWindowOnTop(*LAUNCHER_TITLE)
.then()
.showsAppWindowOnTop("Snapshot", testApp.getPackage())
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 024983d68b21..559d95376b65 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -66,6 +66,18 @@ class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun focusChanges() {
+ super.focusChanges()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 62b9b81ac35d..ad7ee3030ea8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -25,7 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
import org.junit.Test
@@ -70,8 +70,8 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
@Postsubmit
@Test
- override fun wallpaperWindowBecomesInvisible() {
- testSpec.wallpaperWindowBecomesInvisible()
+ override fun launcherWindowBecomesInvisible() {
+ testSpec.launcherWindowBecomesInvisible()
}
@FlakyTest
@@ -98,6 +98,12 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
super.focusChanges()
}
+ @FlakyTest(bugId = 185400889)
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index cd5c61a5a927..26e77b6c4828 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -19,10 +19,11 @@ package com.android.server.wm.flicker.launch
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.appLayerReplacesLauncher
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusChanges
@@ -39,7 +40,7 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
import org.junit.Test
abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@@ -75,13 +76,13 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
testSpec.navBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible()
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
@@ -93,10 +94,10 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
testSpec.statusBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible()
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
@Presubmit
@@ -134,13 +135,13 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
}
- @Presubmit
+ @FlakyTest
@Test
- open fun appLayerReplacesWallpaperLayer() {
- testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
+ open fun appLayerReplacesLauncher() {
+ testSpec.appLayerReplacesLauncher(testApp.`package`)
}
- @Presubmit
+ @FlakyTest
@Test
open fun appWindowReplacesLauncherAsTopWindow() {
testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
@@ -148,7 +149,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- open fun wallpaperWindowBecomesInvisible() {
- testSpec.wallpaperWindowBecomesInvisible()
+ open fun launcherWindowBecomesInvisible() {
+ testSpec.launcherWindowBecomesInvisible()
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 38af8a7d24df..741aad714934 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -71,10 +72,28 @@ class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
@FlakyTest
@Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
+ @Presubmit
+ @Test
+ override fun launcherWindowBecomesInvisible() {
+ super.launcherWindowBecomesInvisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 35ad59751639..5a8162efcb07 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -58,7 +57,13 @@ class ChangeAppRotationTest(
super.focusDoesNotChange()
}
- @Presubmit
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
+ @FlakyTest
@Test
fun screenshotLayerBecomesInvisible() {
testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 298903570e76..ab8ebd923fd3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -36,6 +36,7 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.Test
abstract class RotationTransition(protected val testSpec: FlickerTestParameter) {
@@ -68,16 +69,16 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
}
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarWindowIsAlwaysVisible() {
testSpec.navBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible()
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = true)
}
@FlakyTest
@@ -87,16 +88,16 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
testSpec.config.startRotation, testSpec.config.endRotation)
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarWindowIsAlwaysVisible() {
testSpec.statusBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible()
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = true)
}
@FlakyTest
@@ -110,7 +111,12 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
@Test
open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers = listOf(WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
+ "SecondaryHomeHandle"
+ )
+ )
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index fe444bdecba7..a353c5962582 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -24,7 +23,6 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
-import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.Test
@@ -60,27 +58,37 @@ class SeamlessAppRotationTest(
@FlakyTest(bugId = 140855415)
@Test
- override fun navBarLayerRotatesAndScales() {
- super.navBarLayerRotatesAndScales()
+ override fun statusBarWindowIsAlwaysVisible() {
+ super.statusBarWindowIsAlwaysVisible()
}
@FlakyTest(bugId = 140855415)
@Test
- override fun statusBarLayerRotatesScales() {
- super.statusBarLayerRotatesScales()
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest(bugId = 185400889)
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
+ @FlakyTest(bugId = 185400889)
@Test
fun appLayerAlwaysVisible() {
- testSpec.layerAlwaysVisible(testApp.`package`)
+ testSpec.assertLayers {
+ isVisible(testApp.`package`)
+ }
}
- @Presubmit
+ @FlakyTest(bugId = 185400889)
@Test
fun appLayerRotates() {
testSpec.assertLayers {
this.coversExactly(startingPos, testApp.`package`)
+ .then()
+ .coversExactly(endingPos, testApp.`package`)
}
}
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
index d573e93e4a4c..4f116698ba72 100644
--- a/tests/UpdatableSystemFontTest/AndroidTest.xml
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -19,6 +19,11 @@
<!-- This test requires root to side load fs-verity cert. -->
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="EmojiRenderingTestApp.apk" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
new file mode 100644
index 000000000000..ed34fa9fc1d0
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "EmojiRenderingTestApp",
+ manifest: "AndroidManifest.xml",
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
new file mode 100644
index 000000000000..5d8f5fc2da93
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.emojirenderingtestapp">
+ <application>
+ <activity android:name=".EmojiRenderingTestActivity"/>
+ </application>
+</manifest>
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
new file mode 100644
index 000000000000..947e9c2ff56a
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.emojirenderingtestapp;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/** Test app to render an emoji. */
+public class EmojiRenderingTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout container = new LinearLayout(this);
+ container.setOrientation(LinearLayout.VERTICAL);
+ TextView textView = new TextView(this);
+ textView.setText("\uD83E\uDD72"); // 🥲
+ container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(container);
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index e68455612c7e..032da3f0af75 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -36,7 +36,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -47,6 +46,9 @@ import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
+ private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
+ private static final String DATA_FONTS_DIR = "/data/fonts/files/";
+
private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der";
private static final Pattern PATTERN_FONT = Pattern.compile("path = ([^, \n]*)");
@@ -72,6 +74,14 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG =
"/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig";
+ private static final String EMOJI_RENDERING_TEST_APP_ID = "com.android.emojirenderingtestapp";
+ private static final String EMOJI_RENDERING_TEST_ACTIVITY =
+ EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity";
+
+ private interface ThrowingSupplier<T> {
+ T get() throws Exception;
+ }
+
@Rule
public final AddFsVerityCertRule mAddFsverityCertRule =
new AddFsVerityCertRule(this, CERT_PATH);
@@ -91,7 +101,10 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data/fonts/files/");
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+ // The updated font should be readable and unmodifiable.
+ expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
+ expectRemoteCommandToFail("echo -n '' >> " + fontPath);
}
@Test
@@ -102,8 +115,12 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath2).startsWith("/data/fonts/files/");
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
assertThat(fontPath2).isNotEqualTo(fontPath);
+ // The new file should be readable.
+ expectRemoteCommandToSucceed("cat " + fontPath2 + " > /dev/null");
+ // The old file should be still readable.
+ expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
}
@Test
@@ -119,25 +136,14 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data/fonts/files/");
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
assertThat(fontPath2).isNotEqualTo(fontPath);
- assertThat(fontPath2).startsWith("/data/fonts/files/");
- assertThat(fontPath3).startsWith("/data/fonts/files/");
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath3).startsWith(DATA_FONTS_DIR);
assertThat(fontPath3).isNotEqualTo(fontPath);
}
@Test
- public void updatedFont_dataFileIsImmutableAndReadable() throws Exception {
- expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
- String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data");
-
- expectRemoteCommandToFail("echo -n '' >> " + fontPath);
- expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
- }
-
- @Test
public void updateFont_invalidCert() throws Exception {
expectRemoteCommandToFail(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
@@ -158,11 +164,37 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
}
@Test
+ public void launchApp() throws Exception {
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
+ assertThat(fontPath).startsWith(SYSTEM_FONTS_DIR);
+ expectRemoteCommandToSucceed("am force-stop " + EMOJI_RENDERING_TEST_APP_ID);
+ expectRemoteCommandToSucceed("am start-activity -n " + EMOJI_RENDERING_TEST_ACTIVITY);
+ waitUntil(TimeUnit.SECONDS.toMillis(5), () ->
+ isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID));
+ }
+
+ @Test
+ public void launchApp_afterUpdateFont() throws Exception {
+ String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
+ assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
+ expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
+ assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
+ expectRemoteCommandToSucceed("am force-stop " + EMOJI_RENDERING_TEST_APP_ID);
+ expectRemoteCommandToSucceed("am start-activity -n " + EMOJI_RENDERING_TEST_ACTIVITY);
+ // The original font should NOT be opened by the app.
+ waitUntil(TimeUnit.SECONDS.toMillis(5), () ->
+ isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID)
+ && !isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID));
+ }
+
+ @Test
public void reboot() throws Exception {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data/fonts/files/");
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
expectRemoteCommandToSucceed("stop");
expectRemoteCommandToSucceed("start");
@@ -210,16 +242,40 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
});
}
- private void waitUntil(long timeoutMillis, Supplier<Boolean> func) {
+ private void waitUntil(long timeoutMillis, ThrowingSupplier<Boolean> func) {
long untilMillis = System.currentTimeMillis() + timeoutMillis;
do {
- if (func.get()) return;
try {
+ if (func.get()) return;
Thread.sleep(100);
} catch (InterruptedException e) {
throw new AssertionError("Interrupted", e);
+ } catch (Exception e) {
+ throw new AssertionError("Unexpected exception", e);
}
} while (System.currentTimeMillis() < untilMillis);
throw new AssertionError("Timed out");
}
+
+ private boolean isFileOpenedBy(String path, String appId) throws DeviceNotAvailableException {
+ String pid = pidOf(appId);
+ if (pid.isEmpty()) {
+ return false;
+ }
+ CommandResult result = getDevice().executeShellV2Command(
+ String.format("lsof -t -p %s '%s'", pid, path));
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ return false;
+ }
+ // The file is open if the output of lsof is non-empty.
+ return !result.getStdout().trim().isEmpty();
+ }
+
+ private String pidOf(String appId) throws DeviceNotAvailableException {
+ CommandResult result = getDevice().executeShellV2Command("pidof " + appId);
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ return "";
+ }
+ return result.getStdout().trim();
+ }
}
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
index 56f9df78c83e..39c424e31f0e 100644
--- a/tests/net/integration/Android.bp
+++ b/tests/net/integration/Android.bp
@@ -25,6 +25,7 @@ package {
android_test {
name: "FrameworksNetIntegrationTests",
+ defaults: ["framework-connectivity-test-defaults"],
platform_apis: true,
certificate: "platform",
srcs: [
@@ -61,6 +62,7 @@ android_test {
// Utilities for testing framework code both in integration and unit tests.
java_library {
name: "frameworks-net-integration-testutils",
+ defaults: ["framework-connectivity-test-defaults"],
srcs: ["util/**/*.java", "util/**/*.kt"],
static_libs: [
"androidx.annotation_annotation",
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 47e4b5e4942a..1b0a500c6ac6 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -9768,7 +9768,8 @@ public class ConnectivityServiceTest {
return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
nc, new NetworkScore.Builder().setLegacyInt(0).build(),
mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
- INVALID_UID, mQosCallbackTracker, new ConnectivityService.Dependencies());
+ INVALID_UID, TEST_LINGER_DELAY_MS, mQosCallbackTracker,
+ new ConnectivityService.Dependencies());
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 116d755e30a4..36e229d8aa73 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -71,6 +71,8 @@ public class LingerMonitorTest {
static final int LOW_DAILY_LIMIT = 2;
static final int HIGH_DAILY_LIMIT = 1000;
+ private static final int TEST_LINGER_DELAY_MS = 400;
+
LingerMonitor mMonitor;
@Mock ConnectivityService mConnService;
@@ -366,7 +368,7 @@ public class LingerMonitorTest {
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
- mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
+ mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), TEST_LINGER_DELAY_MS,
mQosCallbackTracker, new ConnectivityService.Dependencies());
nai.everValidated = true;
return nai;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index a2223e8c1e9a..95a972652bf4 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -89,7 +89,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
mNetworkAgent = mock(VcnNetworkAgent.class);
doReturn(mNetworkAgent)
.when(mDeps)
- .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
+ .newNetworkAgent(any(), any(), any(), any(), any(), any(), any(), any(), any());
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
@@ -216,7 +216,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
any(),
any(),
any(),
- anyInt(),
+ any(),
any(),
any(),
any(),
@@ -244,7 +244,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
any(String.class),
ncCaptor.capture(),
lpCaptor.capture(),
- anyInt(),
+ any(),
argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
any(),
any(),
@@ -297,7 +297,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
startingInternalAddrs.equals(lp.getLinkAddresses())
&& Collections.singletonList(TEST_DNS_ADDR)
.equals(lp.getDnsServers())),
- anyInt(),
+ any(),
any(),
any(),
any(),
@@ -356,7 +356,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
any(),
any(),
any(),
- anyInt(),
+ any(),
any(),
any(),
unwantedCallbackCaptor.capture(),
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 5f27fabb62b0..ac0edaa3b579 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -65,6 +65,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
TEST_SUBSCRIPTION_SNAPSHOT,
mConfig,
mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
mDeps);
vgc.setIsQuitting(true);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index ced8745e89c9..9705f0fc6bbc 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
@@ -89,7 +91,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong());
}
- private void verifyBuildNetworkCapabilitiesCommon(int transportType) {
+ private void verifyBuildNetworkCapabilitiesCommon(
+ int transportType, boolean isMobileDataEnabled) {
final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder();
capBuilder.addTransportType(transportType);
capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
@@ -109,10 +112,22 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
capBuilder.build(), new LinkProperties(), false);
final NetworkCapabilities vcnCaps =
VcnGatewayConnection.buildNetworkCapabilities(
- VcnGatewayConnectionConfigTest.buildTestConfig(), record);
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ record,
+ isMobileDataEnabled);
+
assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+ if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) {
+ assertEquals(isMobileDataEnabled, vcnCaps.hasCapability(cap));
+ } else {
+ assertTrue(vcnCaps.hasCapability(cap));
+ }
+ }
+
assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
@@ -126,12 +141,17 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
@Test
public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception {
- verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI);
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI, true /* isMobileDataEnabled */);
}
@Test
public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception {
- verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR);
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, true /* isMobileDataEnabled */);
+ }
+
+ @Test
+ public void testBuildNetworkCapabilitiesMobileDataDisabled() throws Exception {
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 98d553dab01a..284f1f88658e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -202,6 +202,7 @@ public class VcnGatewayConnectionTestBase {
TEST_SUBSCRIPTION_SNAPSHOT,
mConfig,
mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
mDeps);
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
index f943f34c9d52..72db55b3f4c5 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
@@ -16,12 +16,18 @@
package com.android.server.vcn;
+import static android.net.NetworkProvider.NetworkOfferCallback;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.os.test.TestLooper;
@@ -33,18 +39,23 @@ import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.List;
/** Tests for TelephonySubscriptionTracker */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnNetworkProviderTest {
private static final int TEST_SCORE_UNSATISFIED = 0;
- private static final int TEST_SCORE_HIGH = 100;
private static final int TEST_PROVIDER_ID = 1;
@NonNull private final Context mContext;
@NonNull private final TestLooper mTestLooper;
+ @NonNull private VcnNetworkProvider.Dependencies mDeps;
+ @NonNull private ConnectivityManager mConnMgr;
@NonNull private VcnNetworkProvider mVcnNetworkProvider;
@NonNull private NetworkRequestListener mListener;
@@ -55,27 +66,48 @@ public class VcnNetworkProviderTest {
@Before
public void setUp() throws Exception {
- mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper());
+ mDeps = mock(VcnNetworkProvider.Dependencies.class);
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper(), mDeps);
mListener = mock(NetworkRequestListener.class);
}
- @Test
- public void testRequestsPassedToRegisteredListeners() throws Exception {
- mVcnNetworkProvider.registerListener(mListener);
+ private NetworkOfferCallback verifyRegisterAndGetOfferCallback() throws Exception {
+ mVcnNetworkProvider.register();
+
+ final ArgumentCaptor<NetworkOfferCallback> cbCaptor =
+ ArgumentCaptor.forClass(NetworkOfferCallback.class);
+
+ verify(mConnMgr).registerNetworkProvider(eq(mVcnNetworkProvider));
+ verify(mDeps)
+ .registerNetworkOffer(
+ eq(mVcnNetworkProvider),
+ argThat(
+ score ->
+ score.getLegacyInt()
+ == Vcn.getNetworkScore().getLegacyInt()),
+ any(),
+ any(),
+ cbCaptor.capture());
+
+ return cbCaptor.getValue();
+ }
- final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
- verify(mListener).onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
+ @Test
+ public void testRegister() throws Exception {
+ verifyRegisterAndGetOfferCallback();
}
@Test
- public void testRequestsPassedToRegisteredListeners_satisfiedByHighScoringProvider()
- throws Exception {
+ public void testRequestsPassedToRegisteredListeners() throws Exception {
mVcnNetworkProvider.registerListener(mListener);
final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID);
- verify(mListener).onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
+ verify(mListener).onNetworkRequested(request);
}
@Test
@@ -84,7 +116,33 @@ public class VcnNetworkProviderTest {
mVcnNetworkProvider.unregisterListener(mListener);
final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
+ verifyNoMoreInteractions(mListener);
+ }
+
+ @Test
+ public void testCachedRequestsPassedOnRegister() throws Exception {
+ final List<NetworkRequest> requests = new ArrayList<>();
+ final NetworkOfferCallback offerCb = verifyRegisterAndGetOfferCallback();
+
+ for (int i = 0; i < 10; i++) {
+ // Build unique network requests; in this case, iterate down the capabilities as a way
+ // to unique-ify requests.
+ final NetworkRequest request =
+ new NetworkRequest.Builder().clearCapabilities().addCapability(i).build();
+
+ requests.add(request);
+ offerCb.onNetworkNeeded(request);
+ }
+
+ // Remove one, and verify that it is never sent to the listeners.
+ final NetworkRequest removed = requests.remove(0);
+ offerCb.onNetworkUnneeded(removed);
+
+ mVcnNetworkProvider.registerListener(mListener);
+ for (NetworkRequest request : requests) {
+ verify(mListener).onNetworkRequested(request);
+ }
verifyNoMoreInteractions(mListener);
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 90eb75e865e7..736fabdb1ac5 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -16,16 +16,24 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static com.android.server.vcn.Vcn.VcnContentResolver;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -35,12 +43,16 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.database.ContentObserver;
import android.net.NetworkRequest;
+import android.net.Uri;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.os.ParcelUuid;
import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
import android.util.ArraySet;
import com.android.server.VcnManagementService.VcnCallback;
@@ -53,23 +65,31 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
public class VcnTest {
private static final String PKG_NAME = VcnTest.class.getPackage().getName();
private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
- private static final int NETWORK_SCORE = 0;
- private static final int PROVIDER_ID = 5;
+ private static final boolean MOBILE_DATA_ENABLED = true;
+ private static final Set<Integer> TEST_SUB_IDS_IN_GROUP =
+ new ArraySet<>(Arrays.asList(1, 2, 3));
private static final int[][] TEST_CAPS =
new int[][] {
- new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET},
- new int[] {NET_CAPABILITY_DUN}
+ new int[] {NET_CAPABILITY_IMS, NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN},
+ new int[] {NET_CAPABILITY_CBS, NET_CAPABILITY_INTERNET},
+ new int[] {NET_CAPABILITY_FOTA, NET_CAPABILITY_DUN},
+ new int[] {NET_CAPABILITY_MMS}
};
private Context mContext;
private VcnContext mVcnContext;
+ private TelephonyManager mTelephonyManager;
+ private VcnContentResolver mContentResolver;
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
private VcnNetworkProvider mVcnNetworkProvider;
private VcnCallback mVcnCallback;
@@ -86,6 +106,9 @@ public class VcnTest {
public void setUp() {
mContext = mock(Context.class);
mVcnContext = mock(VcnContext.class);
+ mTelephonyManager =
+ setupAndGetTelephonyManager(MOBILE_DATA_ENABLED /* isMobileDataEnabled */);
+ mContentResolver = mock(VcnContentResolver.class);
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
mVcnCallback = mock(VcnCallback.class);
@@ -97,12 +120,15 @@ public class VcnTest {
doReturn(mContext).when(mVcnContext).getContext();
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+ doReturn(mContentResolver).when(mDeps).newVcnContentResolver(eq(mVcnContext));
// Setup VcnGatewayConnection instance generation
doAnswer((invocation) -> {
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
return mock(VcnGatewayConnection.class);
- }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any());
+ }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any(), anyBoolean());
+
+ doReturn(TEST_SUB_IDS_IN_GROUP).when(mSubscriptionSnapshot).getAllSubIdsInGroup(any());
mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
@@ -123,6 +149,16 @@ public class VcnTest {
mDeps);
}
+ private TelephonyManager setupAndGetTelephonyManager(boolean isMobileDataEnabled) {
+ final TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, telephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
+ doReturn(isMobileDataEnabled).when(telephonyManager).isDataEnabled();
+
+ return telephonyManager;
+ }
+
private NetworkRequestListener verifyAndGetRequestListener() {
ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
ArgumentCaptor.forClass(NetworkRequestListener.class);
@@ -139,7 +175,7 @@ public class VcnTest {
requestBuilder.addCapability(netCapability);
}
- requestListener.onNetworkRequested(requestBuilder.build(), NETWORK_SCORE, PROVIDER_ID);
+ requestListener.onNetworkRequested(requestBuilder.build());
mTestLooper.dispatchAll();
}
@@ -164,6 +200,39 @@ public class VcnTest {
}
@Test
+ public void testContentObserverRegistered() {
+ // Validate state from setUp()
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
+ verify(mContentResolver)
+ .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class));
+ }
+
+ @Test
+ public void testMobileDataStateCheckedOnInitialization_enabled() {
+ // Validate state from setUp()
+ assertTrue(mVcn.isMobileDataEnabled());
+ verify(mTelephonyManager).isDataEnabled();
+ }
+
+ @Test
+ public void testMobileDataStateCheckedOnInitialization_disabled() {
+ // Build and setup new telephonyManager to ensure method call count is reset.
+ final TelephonyManager telephonyManager =
+ setupAndGetTelephonyManager(false /* isMobileDataEnabled */);
+ final Vcn vcn =
+ new Vcn(
+ mVcnContext,
+ TEST_SUB_GROUP,
+ mConfig,
+ mSubscriptionSnapshot,
+ mVcnCallback,
+ mDeps);
+
+ assertFalse(vcn.isMobileDataEnabled());
+ verify(mTelephonyManager).isDataEnabled();
+ }
+
+ @Test
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
}
@@ -193,7 +262,8 @@ public class VcnTest {
eq(TEST_SUB_GROUP),
eq(mSubscriptionSnapshot),
any(),
- mGatewayStatusCallbackCaptor.capture());
+ mGatewayStatusCallbackCaptor.capture(),
+ eq(MOBILE_DATA_ENABLED));
return gatewayConnections;
}
@@ -256,20 +326,21 @@ public class VcnTest {
mTestLooper.dispatchAll();
// Verify that the VCN requests the networkRequests be resent
- assertEquals(1, mVcn.getVcnGatewayConnections().size());
+ assertEquals(gatewayConnections.size() - 1, mVcn.getVcnGatewayConnections().size());
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
// Verify that the VcnGatewayConnection is restarted if a request exists for it
triggerVcnRequestListeners(requestListener);
mTestLooper.dispatchAll();
- assertEquals(2, mVcn.getVcnGatewayConnections().size());
+ assertEquals(gatewayConnections.size(), mVcn.getVcnGatewayConnections().size());
verify(mDeps, times(gatewayConnections.size() + 1))
.newVcnGatewayConnection(
eq(mVcnContext),
eq(TEST_SUB_GROUP),
eq(mSubscriptionSnapshot),
any(),
- mGatewayStatusCallbackCaptor.capture());
+ mGatewayStatusCallbackCaptor.capture(),
+ anyBoolean());
}
@Test
@@ -286,7 +357,7 @@ public class VcnTest {
public void testUpdateConfigReevaluatesGatewayConnections() {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
startGatewaysAndGetGatewayConnections(requestListener);
- assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
+ assertEquals(TEST_CAPS.length, mVcn.getVcnGatewayConnectionConfigMap().size());
// Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
// down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
@@ -309,4 +380,57 @@ public class VcnTest {
verify(removedGatewayConnection).teardownAsynchronously();
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
}
+
+ private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) {
+ final ArgumentCaptor<ContentObserver> captor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture());
+ final ContentObserver contentObserver = captor.getValue();
+
+ // Start VcnGatewayConnections
+ mVcn.setMobileDataEnabled(startingToggleState);
+ triggerVcnRequestListeners(verifyAndGetRequestListener());
+ final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> gateways =
+ mVcn.getVcnGatewayConnectionConfigMap();
+
+ // Trigger data toggle change.
+ doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled();
+ contentObserver.onChange(false /* selfChange, ignored */);
+ mTestLooper.dispatchAll();
+
+ // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the
+ // toggle state changed.
+ for (Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry : gateways.entrySet()) {
+ final Set<Integer> exposedCaps = entry.getKey().getAllExposedCapabilities();
+ if (startingToggleState != endingToggleState
+ && (exposedCaps.contains(NET_CAPABILITY_INTERNET)
+ || exposedCaps.contains(NET_CAPABILITY_DUN))) {
+ verify(entry.getValue()).teardownAsynchronously();
+ } else {
+ verify(entry.getValue(), never()).teardownAsynchronously();
+ }
+ }
+
+ assertEquals(endingToggleState, mVcn.isMobileDataEnabled());
+ }
+
+ @Test
+ public void testMobileDataEnabled() {
+ verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataDisabled() {
+ verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataObserverFiredWithoutChanges_dataEnabled() {
+ verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataObserverFiredWithoutChanges_dataDisabled() {
+ verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */);
+ }
}
diff --git a/tools/hiddenapi/checksorted_sha.sh b/tools/hiddenapi/checksorted_sha.sh
index 451fed6be353..72fb86737488 100755
--- a/tools/hiddenapi/checksorted_sha.sh
+++ b/tools/hiddenapi/checksorted_sha.sh
@@ -1,10 +1,10 @@
#!/bin/bash
set -e
LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
-git show --name-only --pretty=format: $1 | grep "boot/hiddenapi/hiddenapi-.*txt" | while read file; do
+git show --name-only --pretty=format: $1 | grep "hiddenapi/hiddenapi-.*txt" | while read file; do
diff <(git show $1:$file) <(git show $1:$file | $LOCAL_DIR/sort_api.sh ) || {
echo -e "\e[1m\e[31m$file $1 is not sorted or contains duplicates. To sort it correctly:\e[0m"
- echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $2/frameworks/base/$file\e[0m"
+ echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $PWD/$file\e[0m"
exit 1
}
done
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 822aba4ee43b..8b18f9b1920e 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -10,7 +10,6 @@ LIBCORE_PACKAGES="\
android.system \
android.test \
com.android.bouncycastle \
- com.android.i18n.phonenumbers \
com.android.okhttp \
com.sun \
dalvik \