summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp58
-rw-r--r--Android.bp2
-rw-r--r--OWNERS4
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java6
-rw-r--r--apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java76
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java15
-rw-r--r--api/Android.bp2
-rw-r--r--boot/Android.bp4
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java4
-rw-r--r--cmds/idmap2/libidmap2/XmlParser.cpp2
-rw-r--r--core/api/current.txt40
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/api/test-current.txt22
-rw-r--r--core/java/android/app/Notification.java17
-rw-r--r--core/java/android/app/SystemServiceRegistry.java5
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java5
-rw-r--r--core/java/android/app/search/SearchSession.java2
-rw-r--r--core/java/android/companion/AssociationInfo.java284
-rw-r--r--core/java/android/content/res/Element.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java152
-rw-r--r--core/java/android/hardware/Camera.java131
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java13
-rw-r--r--core/java/android/hardware/biometrics/PromptInfo.java11
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java8
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java55
-rw-r--r--core/java/android/hardware/camera2/camera_platform.aconfig8
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java37
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java17
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java28
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java2
-rw-r--r--core/java/android/os/BatteryStats.java202
-rw-r--r--core/java/android/os/BatteryUsageStats.java2
-rwxr-xr-xcore/java/android/os/Build.java2
-rw-r--r--core/java/android/os/DropBoxManager.java2
-rw-r--r--core/java/android/os/SystemVibrator.java308
-rw-r--r--core/java/android/os/VibratorInfo.java15
-rw-r--r--core/java/android/os/vibrator/MultiVibratorInfo.java294
-rw-r--r--core/java/android/os/vibrator/VibratorInfoFactory.java52
-rw-r--r--core/java/android/provider/Settings.java30
-rw-r--r--core/java/android/service/quicksettings/Tile.java18
-rw-r--r--core/java/android/util/IntArray.java5
-rw-r--r--core/java/android/view/IRecentsAnimationRunner.aidl3
-rw-r--r--core/java/android/view/InputWindowHandle.java14
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java23
-rw-r--r--core/java/android/view/InsetsController.java52
-rw-r--r--core/java/android/view/InsetsSource.java5
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java14
-rw-r--r--core/java/android/widget/TextView.java15
-rw-r--r--core/java/android/window/WindowInfosListenerForTest.java4
-rw-r--r--core/java/android/window/flags/windowing_sdk.aconfig10
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistory.java355
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistoryIterator.java157
-rw-r--r--core/java/com/android/internal/os/LongArrayMultiStateCounter.java32
-rw-r--r--core/java/com/android/internal/os/MultiStateStats.java303
-rw-r--r--core/java/com/android/internal/os/OWNERS1
-rw-r--r--core/java/com/android/internal/os/PowerStats.java327
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java83
-rw-r--r--core/java/com/android/internal/widget/MessagingData.java70
-rw-r--r--core/java/com/android/internal/widget/MessagingLayout.java73
-rw-r--r--core/jni/android_content_res_ObbScanner.cpp2
-rw-r--r--core/jni/android_hardware_SensorManager.cpp2
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp41
-rw-r--r--core/jni/android_util_AssetManager.cpp4
-rw-r--r--core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp12
-rw-r--r--core/jni/jni_common.cpp9
-rw-r--r--core/jni/jni_common.h1
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/values/config.xml20
-rw-r--r--core/res/res/values/config_battery_stats.xml34
-rw-r--r--core/res/res/values/config_telephony.xml2
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/coretests/res/values-id/strings.xml5
-rw-r--r--core/tests/coretests/res/values-in/strings.xml5
-rw-r--r--core/tests/coretests/res/values/strings.xml7
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java5
-rw-r--r--core/tests/coretests/src/android/app/activity/BroadcastTest.java31
-rw-r--r--core/tests/coretests/src/android/app/activity/IntentSenderTest.java4
-rw-r--r--core/tests/coretests/src/android/app/activity/LaunchpadActivity.java3
-rw-r--r--core/tests/coretests/src/android/app/activity/LocalDeniedReceiver.java4
-rw-r--r--core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java21
-rw-r--r--core/tests/coretests/src/android/service/TEST_MAPPING18
-rw-r--r--core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java2
-rw-r--r--core/tests/coretests/src/android/service/euicc/OWNERS1
-rw-r--r--core/tests/coretests/src/android/service/quicksettings/TileTest.java67
-rw-r--r--core/tests/coretests/src/android/window/flags/WindowFlagsTest.java45
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java132
-rw-r--r--core/tests/utiltests/src/android/util/IntArrayTest.java3
-rw-r--r--core/tests/vibrator/src/android/os/VibratorInfoTest.java27
-rw-r--r--core/tests/vibrator/src/android/os/VibratorTest.java333
-rw-r--r--core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java361
-rw-r--r--core/tests/vibrator/src/android/os/vibrator/VibratorInfoFactoryTest.java130
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml56
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml14
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt74
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt148
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt232
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt65
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMediaController.kt365
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java)88
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java369
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt87
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java32
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java4
-rw-r--r--libs/androidfw/AssetManager.cpp134
-rw-r--r--libs/androidfw/BackupData.cpp6
-rw-r--r--libs/androidfw/BackupHelpers.cpp76
-rw-r--r--libs/androidfw/ConfigDescription.cpp2
-rw-r--r--libs/androidfw/CursorWindow.cpp2
-rw-r--r--libs/androidfw/ObbFile.cpp4
-rw-r--r--libs/androidfw/ResourceTypes.cpp128
-rw-r--r--libs/androidfw/include/androidfw/Asset.h2
-rw-r--r--libs/androidfw/include/androidfw/ConfigDescription.h2
-rw-r--r--libs/androidfw/tests/BackupData_test.cpp34
-rw-r--r--libs/androidfw/tests/CommonHelpers.cpp2
-rw-r--r--libs/androidfw/tests/ConfigDescription_test.cpp26
-rw-r--r--libs/androidfw/tests/ObbFile_test.cpp10
-rw-r--r--libs/androidfw/tests/ResTable_test.cpp4
-rw-r--r--libs/androidfw/tests/Split_test.cpp4
-rw-r--r--libs/androidfw/tests/TestHelpers.cpp4
-rw-r--r--libs/hwui/Android.bp19
-rw-r--r--libs/hwui/aconfig/hwui_flags.aconfig8
-rw-r--r--libs/hwui/utils/LinearAllocator.cpp18
-rw-r--r--libs/input/Android.bp14
-rw-r--r--libs/input/MouseCursorController.cpp14
-rw-r--r--libs/input/PointerController.cpp10
-rw-r--r--libs/input/PointerController.h7
-rw-r--r--libs/input/PointerControllerContext.cpp8
-rw-r--r--libs/input/PointerControllerContext.h6
-rw-r--r--libs/input/SpriteController.cpp72
-rw-r--r--libs/input/SpriteController.h30
-rw-r--r--libs/input/TouchSpotController.cpp16
-rw-r--r--libs/input/tests/PointerController_test.cpp16
-rw-r--r--media/java/android/media/AudioManager.java91
-rw-r--r--media/java/android/media/IAudioService.aidl17
-rw-r--r--media/java/android/media/projection/IMediaProjectionManager.aidl1
-rw-r--r--media/java/android/media/session/MediaSessionManager.java2
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java2
-rw-r--r--native/android/performance_hint.cpp2
-rw-r--r--packages/CtsShim/build/Android.bp19
-rw-r--r--packages/CtsShim/build/shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml31
-rw-r--r--packages/CtsShim/build/shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java (renamed from packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt)30
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java2
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt3
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt6
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsThemeTest.kt6
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedTextTest.kt2
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt2
-rw-r--r--packages/SettingsLib/Spa/testutils/Android.bp2
-rw-r--r--packages/SettingsLib/Spa/testutils/build.gradle.kts7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java20
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/dpp/WifiDppIntentHelper.java5
-rw-r--r--packages/SettingsLib/tests/robotests/Android.bp35
-rw-r--r--packages/SettingsLib/tests/robotests/config/robolectric.properties1
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/Android.bp40
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/BUILD69
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/build.gradle48
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java348
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java (renamed from packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/MockitoHelper.kt)16
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml6
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java360
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml9
-rw-r--r--packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml20
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java69
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java8
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java20
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java10
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java99
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java21
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java2
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java86
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java35
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java2
-rw-r--r--packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java41
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java11
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java41
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml4
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml4
-rw-r--r--packages/SystemUI/docs/qs-tiles.md2
-rw-r--r--packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml42
-rw-r--r--packages/SystemUI/res/drawable/auth_credential_emergency_button_background.xml22
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml2
-rw-r--r--packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml101
-rw-r--r--packages/SystemUI/res/layout-land/auth_credential_password_view.xml63
-rw-r--r--packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml45
-rw-r--r--packages/SystemUI/res/layout-land/auth_credential_pin_view.xml28
-rw-r--r--packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml104
-rw-r--r--packages/SystemUI/res/layout/auth_credential_password_view.xml67
-rw-r--r--packages/SystemUI/res/layout/auth_credential_pattern_view.xml44
-rw-r--r--packages/SystemUI/res/layout/auth_credential_pin_view.xml28
-rw-r--r--packages/SystemUI/res/layout/internet_connectivity_dialog.xml22
-rw-r--r--packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml4
-rw-r--r--packages/SystemUI/res/values/attrs.xml1
-rw-r--r--packages/SystemUI/res/values/ids.xml9
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/res/values/styles.xml19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java3
-rw-r--r--packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt3
-rw-r--r--packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt109
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/IPinPad.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PinPadViewBinder.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt (renamed from packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintIconViewBinder.kt)21
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt (renamed from packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt)30
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java (renamed from packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicRelease.java (renamed from packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java149
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt77
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModelTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt)38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt)303
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt)58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt94
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java177
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt82
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java123
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt118
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt40
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/InlineSuggestionRendorInfoCallbackOnResultListener.java65
-rw-r--r--services/autofill/java/com/android/server/autofill/InlineSuggestionRequestConsumer.java55
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java66
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java40
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java12
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java3
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java40
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java59
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java10
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java105
-rw-r--r--services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java260
-rw-r--r--services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java (renamed from services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java)102
-rw-r--r--services/backup/java/com/android/server/backup/utils/TarBackupReader.java86
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java4
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java8
-rw-r--r--services/companion/java/com/android/server/companion/virtual/Android.bp12
-rw-r--r--services/companion/java/com/android/server/companion/virtual/flags.aconfig8
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java2
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java8
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java38
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java3
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java70
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java70
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java79
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java15
-rw-r--r--services/core/java/com/android/server/audio/FocusRequester.java11
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java152
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java11
-rw-r--r--services/core/java/com/android/server/input/GestureMonitorSpyWindow.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java11
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java9
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java17
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java8
-rw-r--r--services/core/java/com/android/server/location/injector/SettingsHelper.java20
-rw-r--r--services/core/java/com/android/server/location/injector/SystemSettingsHelper.java8
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java53
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java7
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java8
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java56
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java42
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java5
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java34
-rw-r--r--services/core/java/com/android/server/notification/flags.aconfig9
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java9
-rw-r--r--services/core/java/com/android/server/pm/InstantAppResolverConnection.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageMetrics.java29
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java13
-rw-r--r--services/core/java/com/android/server/pm/ResolveIntentHelper.java7
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java54
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java40
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java69
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java56
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java62
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java37
-rw-r--r--services/core/java/com/android/server/pm/pkg/SuspendParams.java4
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java231
-rw-r--r--services/core/java/com/android/server/policy/SingleKeyGestureDetector.java10
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java18
-rw-r--r--services/core/java/com/android/server/power/stats/AggregatedPowerStats.java147
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java48
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java193
-rw-r--r--services/core/java/com/android/server/power/stats/CpuAggregatedPowerStats.java29
-rw-r--r--services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java140
-rw-r--r--services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java121
-rw-r--r--services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java232
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsAggregator.java226
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsCollector.java183
-rw-r--r--services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java2
-rw-r--r--services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java19
-rw-r--r--services/core/java/com/android/server/security/rkp/RemoteProvisioningShellCommand.java84
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java85
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java31
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java7
-rw-r--r--services/core/java/com/android/server/wm/AsyncRotationController.java50
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java22
-rw-r--r--services/core/java/com/android/server/wm/EmbeddedWindowController.java20
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java8
-rw-r--r--services/core/java/com/android/server/wm/InputWindowHandleWrapper.java12
-rw-r--r--services/core/java/com/android/server/wm/NavBarFadeAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java3
-rw-r--r--services/core/java/com/android/server/wm/Task.java12
-rw-r--r--services/core/java/com/android/server/wm/Transition.java5
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java5
-rw-r--r--services/core/jni/Android.bp2
-rw-r--r--services/core/jni/OWNERS1
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp6
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp27
-rw-r--r--services/core/jni/com_android_server_power_stats_CpuPowerStatsCollector.cpp135
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessPolicy.kt2
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessState.kt23
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessUri.kt11
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt169
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt276
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionService.kt194
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java6
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java4
-rw-r--r--services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningShellCommandTest.java140
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java84
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java (renamed from services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java)133
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java2
-rw-r--r--services/tests/powerstatstests/Android.bp2
-rw-r--r--services/tests/powerstatstests/AndroidManifest.xml1
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java89
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java335
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java8
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java137
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java165
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java18
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java7
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java267
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java232
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java88
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt1
-rw-r--r--services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/power/hint/OWNERS2
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java2
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java43
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java164
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java58
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java44
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java41
-rw-r--r--telecomm/java/android/telecom/Call.java12
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java6
-rw-r--r--telephony/java/android/telephony/DisconnectCause.java1
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java29
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java13
-rw-r--r--tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java2
-rw-r--r--tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java2
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java4
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java10
-rw-r--r--tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java2
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml2
-rw-r--r--tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java2
-rw-r--r--tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java8
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java2
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java7
-rw-r--r--tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java2
-rw-r--r--tools/aapt/AaptAssets.cpp146
-rw-r--r--tools/aapt/AaptAssets.h2
-rw-r--r--tools/aapt/AaptConfig.cpp60
-rw-r--r--tools/aapt/AaptUtil.cpp4
-rw-r--r--tools/aapt/ApkBuilder.cpp6
-rw-r--r--tools/aapt/CacheUpdater.h12
-rw-r--r--tools/aapt/Command.cpp260
-rw-r--r--tools/aapt/CrunchCache.cpp2
-rw-r--r--tools/aapt/DirectoryWalker.h4
-rw-r--r--tools/aapt/FileFinder.cpp4
-rw-r--r--tools/aapt/Images.cpp42
-rw-r--r--tools/aapt/Package.cpp68
-rw-r--r--tools/aapt/Resource.cpp372
-rw-r--r--tools/aapt/ResourceFilter.cpp6
-rw-r--r--tools/aapt/ResourceIdCache.cpp2
-rw-r--r--tools/aapt/ResourceTable.cpp502
-rw-r--r--tools/aapt/SourcePos.cpp6
-rw-r--r--tools/aapt/StringPool.cpp28
-rw-r--r--tools/aapt/Symbol.h6
-rw-r--r--tools/aapt/XMLNode.cpp160
-rw-r--r--tools/aapt/pseudolocalize.cpp8
-rw-r--r--tools/aapt2/Debug.cpp2
-rw-r--r--tools/aapt2/cmd/Util.cpp2
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.cpp2
-rw-r--r--tools/aapt2/trace/TraceBuffer.cpp14
-rw-r--r--tools/split-select/Grouper_test.cpp2
-rw-r--r--tools/split-select/Main.cpp38
-rw-r--r--tools/split-select/Rule_test.cpp2
-rw-r--r--tools/split-select/SplitDescription.cpp4
-rw-r--r--tools/split-select/TestRules.cpp5
543 files changed, 15705 insertions, 6157 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
new file mode 100644
index 000000000000..b753aab33dcd
--- /dev/null
+++ b/AconfigFlags.bp
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Aconfig declarations and libraries for the core framework
+java_defaults {
+ name: "framework-minus-apex-aconfig-libraries",
+
+ // Add java_aconfig_libraries to here to add them to the core framework
+ srcs: [
+ ":com.android.hardware.camera2-aconfig-java{.generated_srcjars}",
+ ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
+ ],
+}
+
+// Default flags for java_aconfig_libraries that go into framework-minus-apex
+// These libraries will not work standalone
+java_defaults {
+ name: "framework-minus-apex-aconfig-java-defaults",
+ sdk_version: "core_platform",
+ libs: ["fake_device_config"],
+}
+
+// Camera
+aconfig_declarations {
+ name: "com.android.hardware.camera2-aconfig",
+ package: "com.android.hardware.camera2",
+ srcs: ["core/java/android/hardware/camera2/camera_platform.aconfig"],
+}
+
+java_aconfig_library {
+ name: "com.android.hardware.camera2-aconfig-java",
+ aconfig_declarations: "com.android.hardware.camera2-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// Window
+aconfig_declarations {
+ name: "com.android.window.flags.window-aconfig",
+ package: "com.android.window.flags",
+ srcs: ["core/java/android/window/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "com.android.window.flags.window-aconfig-java",
+ aconfig_declarations: "com.android.window.flags.window-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index be589b2857b4..53554bce43b8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -267,6 +267,7 @@ java_defaults {
defaults: [
"framework-aidl-export-defaults",
"latest_android_hardware_soundtrigger3_java_static",
+ "framework-minus-apex-aconfig-libraries",
],
srcs: [
":framework-non-updatable-sources",
@@ -701,6 +702,7 @@ stubs_defaults {
}
build = [
+ "AconfigFlags.bp",
"ProtoLibraries.bp",
"TestProtoLibraries.bp",
]
diff --git a/OWNERS b/OWNERS
index 8ee488dcb7a2..6c2532445f0f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -16,8 +16,6 @@ narayan@google.com #{LAST_RESORT_SUGGESTION}
ogunwale@google.com #{LAST_RESORT_SUGGESTION}
roosa@google.com #{LAST_RESORT_SUGGESTION}
smoreland@google.com #{LAST_RESORT_SUGGESTION}
-svetoslavganov@android.com #{LAST_RESORT_SUGGESTION}
-svetoslavganov@google.com #{LAST_RESORT_SUGGESTION}
yamasani@google.com #{LAST_RESORT_SUGGESTION}
# API changes are already covered by API-Review+1 (http://mdb/android-api-council)
@@ -30,7 +28,7 @@ per-file */TEST_MAPPING = *
# Support bulk translation updates
per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
-per-file **.bp,**.mk = hansson@google.com
+per-file **.bp,**.mk = hansson@google.com, joeo@google.com
per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 3a05323122ba..5dc994edd635 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -371,7 +371,7 @@ public class JobInfo implements Parcelable {
/**
* Allows this job to run despite doze restrictions as long as the app is in the foreground
- * or on the temporary whitelist
+ * or on the temporary allowlist
* @hide
*/
public static final int FLAG_IMPORTANT_WHILE_FOREGROUND = 1 << 1;
@@ -2044,13 +2044,13 @@ public class JobInfo implements Parcelable {
/**
* Setting this to true indicates that this job is important while the scheduling app
- * is in the foreground or on the temporary whitelist for background restrictions.
+ * is in the foreground or on the temporary allowlist for background restrictions.
* This means that the system will relax doze restrictions on this job during this time.
*
* Apps should use this flag only for short jobs that are essential for the app to function
* properly in the foreground.
*
- * Note that once the scheduling app is no longer whitelisted from background restrictions
+ * Note that once the scheduling app is no longer allowlisted from background restrictions
* and in the background, or the job failed due to unsatisfied constraints,
* this job should be expected to behave like other jobs without this flag.
*
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index 4ce31e96208c..20da1718abb0 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -29,10 +29,10 @@ import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
- * Interface to access and modify the permanent and temporary power save whitelist. The two lists
- * are kept separately. Apps placed on the permanent whitelist are only removed via an explicit
- * removeFromWhitelist call. Apps whitelisted by default by the system cannot be removed. Apps
- * placed on the temporary whitelist are removed from that whitelist after a predetermined amount of
+ * Interface to access and modify the permanent and temporary power save allowlist. The two lists
+ * are kept separately. Apps placed on the permanent allowlist are only removed via an explicit
+ * removeFromAllowlist call. Apps whitelisted by default by the system cannot be removed. Apps
+ * placed on the temporary allowlist are removed from that allowlist after a predetermined amount of
* time.
*
* @deprecated Use {@link PowerExemptionManager} instead
@@ -50,18 +50,18 @@ public class PowerWhitelistManager {
private final PowerExemptionManager mPowerExemptionManager;
/**
- * Indicates that an unforeseen event has occurred and the app should be whitelisted to handle
+ * Indicates that an unforeseen event has occurred and the app should be allowlisted to handle
* it.
*/
public static final int EVENT_UNSPECIFIED = PowerExemptionManager.EVENT_UNSPECIFIED;
/**
- * Indicates that an SMS event has occurred and the app should be whitelisted to handle it.
+ * Indicates that an SMS event has occurred and the app should be allowlisted to handle it.
*/
public static final int EVENT_SMS = PowerExemptionManager.EVENT_SMS;
/**
- * Indicates that an MMS event has occurred and the app should be whitelisted to handle it.
+ * Indicates that an MMS event has occurred and the app should be allowlisted to handle it.
*/
public static final int EVENT_MMS = PowerExemptionManager.EVENT_MMS;
@@ -381,7 +381,7 @@ public class PowerWhitelistManager {
}
/**
- * Add the specified package to the permanent power save whitelist.
+ * Add the specified package to the permanent power save allowlist.
*
* @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(String)} instead
*/
@@ -392,7 +392,7 @@ public class PowerWhitelistManager {
}
/**
- * Add the specified packages to the permanent power save whitelist.
+ * Add the specified packages to the permanent power save allowlist.
*
* @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(List)} instead
*/
@@ -403,10 +403,10 @@ public class PowerWhitelistManager {
}
/**
- * Get a list of app IDs of app that are whitelisted. This does not include temporarily
- * whitelisted apps.
+ * Get a list of app IDs of app that are allowlisted. This does not include temporarily
+ * allowlisted apps.
*
- * @param includingIdle Set to true if the app should be whitelisted from device idle as well
+ * @param includingIdle Set to true if the app should be allowlisted from device idle as well
* as other power save restrictions
* @deprecated Use {@link PowerExemptionManager#getAllowListedAppIds(boolean)} instead
* @hide
@@ -418,10 +418,10 @@ public class PowerWhitelistManager {
}
/**
- * Returns true if the app is whitelisted from power save restrictions. This does not include
- * temporarily whitelisted apps.
+ * Returns true if the app is allowlisted from power save restrictions. This does not include
+ * temporarily allowlisted apps.
*
- * @param includingIdle Set to true if the app should be whitelisted from device
+ * @param includingIdle Set to true if the app should be allowlisted from device
* idle as well as other power save restrictions
* @deprecated Use {@link PowerExemptionManager#isAllowListed(String, boolean)} instead
* @hide
@@ -432,11 +432,11 @@ public class PowerWhitelistManager {
}
/**
- * Remove an app from the permanent power save whitelist. Only apps that were added via
+ * Remove an app from the permanent power save allowlist. Only apps that were added via
* {@link #addToWhitelist(String)} or {@link #addToWhitelist(List)} will be removed. Apps
- * whitelisted by default by the system cannot be removed.
+ * allowlisted by default by the system cannot be removed.
*
- * @param packageName The app to remove from the whitelist
+ * @param packageName The app to remove from the allowlist
* @deprecated Use {@link PowerExemptionManager#removeFromPermanentAllowList(String)} instead
*/
@Deprecated
@@ -446,10 +446,10 @@ public class PowerWhitelistManager {
}
/**
- * Add an app to the temporary whitelist for a short amount of time.
+ * Add an app to the temporary allowlist for a short amount of time.
*
- * @param packageName The package to add to the temp whitelist
- * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
+ * @param packageName The package to add to the temp allowlist
+ * @param durationMs How long to keep the app on the temp allowlist for (in milliseconds)
* @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
* @param reason a optional human readable reason string, could be null or empty string.
* @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
@@ -463,10 +463,10 @@ public class PowerWhitelistManager {
}
/**
- * Add an app to the temporary whitelist for a short amount of time.
+ * Add an app to the temporary allowlist for a short amount of time.
*
- * @param packageName The package to add to the temp whitelist
- * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
+ * @param packageName The package to add to the temp allowlist
+ * @param durationMs How long to keep the app on the temp allowlist for (in milliseconds)
* @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
* String, int, String, long)} instead
*/
@@ -478,15 +478,15 @@ public class PowerWhitelistManager {
}
/**
- * Add an app to the temporary whitelist for a short amount of time for a specific reason. The
- * temporary whitelist is kept separately from the permanent whitelist and apps are
- * automatically removed from the temporary whitelist after a predetermined amount of time.
+ * Add an app to the temporary allowlist for a short amount of time for a specific reason. The
+ * temporary allowlist is kept separately from the permanent allowlist and apps are
+ * automatically removed from the temporary allowlist after a predetermined amount of time.
*
- * @param packageName The package to add to the temp whitelist
- * @param event The reason to add the app to the temp whitelist
- * @param reason A human-readable reason explaining why the app is temp whitelisted. Only
+ * @param packageName The package to add to the temp allowlist
+ * @param event The reason to add the app to the temp allowlist
+ * @param reason A human-readable reason explaining why the app is temp allowlisted. Only
* used for logging purposes. Could be null or empty string.
- * @return The duration (in milliseconds) that the app is whitelisted for
+ * @return The duration (in milliseconds) that the app is allowlisted for
* @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
* String, int, String, int)} instead
*/
@@ -499,16 +499,16 @@ public class PowerWhitelistManager {
}
/**
- * Add an app to the temporary whitelist for a short amount of time for a specific reason. The
- * temporary whitelist is kept separately from the permanent whitelist and apps are
- * automatically removed from the temporary whitelist after a predetermined amount of time.
+ * Add an app to the temporary allowlist for a short amount of time for a specific reason. The
+ * temporary allowlist is kept separately from the permanent allowlist and apps are
+ * automatically removed from the temporary allowlist after a predetermined amount of time.
*
- * @param packageName The package to add to the temp whitelist
- * @param event The reason to add the app to the temp whitelist
+ * @param packageName The package to add to the temp allowlist
+ * @param event The reason to add the app to the temp allowlist
* @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
- * @param reason A human-readable reason explaining why the app is temp whitelisted. Only
+ * @param reason A human-readable reason explaining why the app is temp allowlisted. Only
* used for logging purposes. Could be null or empty string.
- * @return The duration (in milliseconds) that the app is whitelisted for
+ * @return The duration (in milliseconds) that the app is allowlisted for
* @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
* String, int, String, int)} instead
*/
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 098b2fb67360..d48d84ba6980 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -1118,6 +1118,7 @@ public final class JobStore {
}
boolean needFileMigration = false;
long nowElapsed = sElapsedRealtimeClock.millis();
+ int numDuplicates = 0;
synchronized (mLock) {
for (File file : files) {
final AtomicFile aFile = createJobFile(file);
@@ -1126,6 +1127,16 @@ public final class JobStore {
if (jobs != null) {
for (int i = 0; i < jobs.size(); i++) {
JobStatus js = jobs.get(i);
+ final JobStatus existingJob = this.jobSet.get(
+ js.getUid(), js.getNamespace(), js.getJobId());
+ if (existingJob != null) {
+ numDuplicates++;
+ // Jobs are meant to have unique uid-namespace-jobId
+ // combinations, but we've somehow read multiple jobs with the
+ // combination. Drop the latter one since keeping both will
+ // result in other issues.
+ continue;
+ }
js.prepareLocked();
js.enqueueTime = nowElapsed;
this.jobSet.add(js);
@@ -1174,6 +1185,10 @@ public final class JobStore {
migrateJobFilesAsync();
}
+ if (numDuplicates > 0) {
+ Slog.wtf(TAG, "Encountered " + numDuplicates + " duplicate persisted jobs");
+ }
+
// Log the count immediately after loading from boot.
mCurrentJobSetSize = numJobs;
mScheduledJob30MinHighWaterMark = mCurrentJobSetSize;
diff --git a/api/Android.bp b/api/Android.bp
index c16bce5a1aea..e9cc40513221 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -83,6 +83,7 @@ combined_apis {
"framework-configinfrastructure",
"framework-connectivity",
"framework-connectivity-t",
+ "framework-crashrecovery",
"framework-devicelock",
"framework-graphics",
"framework-healthfitness",
@@ -104,6 +105,7 @@ combined_apis {
system_server_classpath: [
"service-art",
"service-configinfrastructure",
+ "service-crashrecovery",
"service-healthfitness",
"service-media-s",
"service-permission",
diff --git a/boot/Android.bp b/boot/Android.bp
index 83a46c522317..93d425e439a9 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -84,6 +84,10 @@ custom_platform_bootclasspath {
module: "com.android.conscrypt-bootclasspath-fragment",
},
{
+ apex: "com.android.crashrecovery",
+ module: "com.android.crashrecovery-bootclasspath-fragment",
+ },
+ {
apex: "com.android.devicelock",
module: "com.android.devicelock-bootclasspath-fragment",
},
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index b6dc32a29f04..9dedf7025143 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -192,7 +192,7 @@ public class Bmgr {
}
if ("whitelist".equals(op)) {
- doPrintWhitelist();
+ doPrintAllowlist();
return;
}
@@ -911,7 +911,7 @@ public class Bmgr {
}
}
- private void doPrintWhitelist() {
+ private void doPrintAllowlist() {
try {
final String[] whitelist = mBmgr.getTransportWhitelist();
if (whitelist != null) {
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 766ca565a23c..1d784600459d 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -109,7 +109,7 @@ Result<std::string> GetStringValue(const ResXMLParser& parser, const Res_value&
switch (value.dataType) {
case Res_value::TYPE_STRING: {
if (auto str = parser.getStrings().string8ObjectAt(value.data); str.ok()) {
- return std::string(str->string());
+ return std::string(str->c_str());
}
break;
}
diff --git a/core/api/current.txt b/core/api/current.txt
index a3d8978caa21..cb929261bde1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -14341,14 +14341,14 @@ package android.database.sqlite {
method @NonNull public static android.database.sqlite.SQLiteDatabase create(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method @NonNull public static android.database.sqlite.SQLiteDatabase createInMemory(@NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
method @NonNull public android.database.sqlite.SQLiteRawStatement createRawStatement(@NonNull String);
- method public int delete(String, String, String[]);
+ method public int delete(@NonNull String, @Nullable String, @Nullable String[]);
method public static boolean deleteDatabase(@NonNull java.io.File);
method public void disableWriteAheadLogging();
method public boolean enableWriteAheadLogging();
method public void endTransaction();
method public void execPerConnectionSQL(@NonNull String, @Nullable Object[]) throws android.database.SQLException;
method public void execSQL(String) throws android.database.SQLException;
- method public void execSQL(String, Object[]) throws android.database.SQLException;
+ method public void execSQL(@NonNull String, @NonNull Object[]) throws android.database.SQLException;
method public static String findEditTable(String);
method public java.util.List<android.util.Pair<java.lang.String,java.lang.String>> getAttachedDbs();
method public long getLastChangedRowCount();
@@ -14360,9 +14360,9 @@ package android.database.sqlite {
method public long getTotalChangedRowCount();
method public int getVersion();
method public boolean inTransaction();
- method public long insert(String, String, android.content.ContentValues);
- method public long insertOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
- method public long insertWithOnConflict(String, String, android.content.ContentValues, int);
+ method public long insert(@NonNull String, @Nullable String, @Nullable android.content.ContentValues);
+ method public long insertOrThrow(@NonNull String, @Nullable String, @Nullable android.content.ContentValues) throws android.database.SQLException;
+ method public long insertWithOnConflict(@NonNull String, @Nullable String, @Nullable android.content.ContentValues, int);
method public boolean isDatabaseIntegrityOk();
method public boolean isDbLockedByCurrentThread();
method @Deprecated public boolean isDbLockedByOtherThreads();
@@ -14379,19 +14379,19 @@ package android.database.sqlite {
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(@NonNull java.io.File, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(@NonNull String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(@NonNull String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, @Nullable android.database.DatabaseErrorHandler);
- method public android.database.Cursor query(boolean, String, String[], String, String[], String, String, String, String);
- method public android.database.Cursor query(boolean, String, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
- method public android.database.Cursor query(String, String[], String, String[], String, String, String);
- method public android.database.Cursor query(String, String[], String, String[], String, String, String, String);
- method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, String, String[], String, String[], String, String, String, String);
- method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, String, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
- method public android.database.Cursor rawQuery(String, String[]);
- method public android.database.Cursor rawQuery(String, String[], android.os.CancellationSignal);
- method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String);
- method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String, android.os.CancellationSignal);
+ method @NonNull public android.database.Cursor query(boolean, @NonNull String, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable String, @Nullable String, @Nullable String);
+ method @NonNull public android.database.Cursor query(boolean, @NonNull String, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable android.os.CancellationSignal);
+ method @NonNull public android.database.Cursor query(@NonNull String, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable String, @Nullable String);
+ method @NonNull public android.database.Cursor query(@NonNull String, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable String, @Nullable String, @Nullable String);
+ method @NonNull public android.database.Cursor queryWithFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, @NonNull String, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable String, @Nullable String, @Nullable String);
+ method @NonNull public android.database.Cursor queryWithFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, @NonNull String, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable android.os.CancellationSignal);
+ method @NonNull public android.database.Cursor rawQuery(@NonNull String, @Nullable String[]);
+ method @NonNull public android.database.Cursor rawQuery(@NonNull String, @Nullable String[], @Nullable android.os.CancellationSignal);
+ method @NonNull public android.database.Cursor rawQueryWithFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, @NonNull String, @Nullable String[], @NonNull String);
+ method @NonNull public android.database.Cursor rawQueryWithFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, @NonNull String, @Nullable String[], @NonNull String, @Nullable android.os.CancellationSignal);
method public static int releaseMemory();
- method public long replace(String, String, android.content.ContentValues);
- method public long replaceOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
+ method public long replace(@NonNull String, @Nullable String, @Nullable android.content.ContentValues);
+ method public long replaceOrThrow(@NonNull String, @Nullable String, @Nullable android.content.ContentValues) throws android.database.SQLException;
method public void setCustomAggregateFunction(@NonNull String, @NonNull java.util.function.BinaryOperator<java.lang.String>) throws android.database.sqlite.SQLiteException;
method public void setCustomScalarFunction(@NonNull String, @NonNull java.util.function.UnaryOperator<java.lang.String>) throws android.database.sqlite.SQLiteException;
method public void setForeignKeyConstraintsEnabled(boolean);
@@ -14402,8 +14402,8 @@ package android.database.sqlite {
method public void setPageSize(long);
method public void setTransactionSuccessful();
method public void setVersion(int);
- method public int update(String, android.content.ContentValues, String, String[]);
- method public int updateWithOnConflict(String, android.content.ContentValues, String, String[], int);
+ method public int update(@NonNull String, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
+ method public int updateWithOnConflict(@NonNull String, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[], int);
method public void validateSql(@NonNull String, @Nullable android.os.CancellationSignal);
method @Deprecated public boolean yieldIfContended();
method public boolean yieldIfContendedSafely();
@@ -44883,6 +44883,7 @@ package android.telephony {
field public static final int OUT_OF_NETWORK = 11; // 0xb
field public static final int OUT_OF_SERVICE = 18; // 0x12
field public static final int POWER_OFF = 17; // 0x11
+ field public static final int SATELLITE_ENABLED = 82; // 0x52
field public static final int SERVER_ERROR = 12; // 0xc
field public static final int SERVER_UNREACHABLE = 9; // 0x9
field public static final int TIMED_OUT = 13; // 0xd
@@ -46007,6 +46008,7 @@ package android.telephony {
field public static final int ERI_FLASH = 2; // 0x2
field public static final int ERI_OFF = 1; // 0x1
field public static final int ERI_ON = 0; // 0x0
+ field public static final String EVENT_DISPLAY_SOS_MESSAGE = "android.telephony.event.DISPLAY_SOS_MESSAGE";
field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT";
field public static final String EXTRA_APN_PROTOCOL = "android.telephony.extra.APN_PROTOCOL";
field public static final String EXTRA_APN_TYPE = "android.telephony.extra.APN_TYPE";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 61415839ea2c..7870cee63588 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -301,6 +301,7 @@ package android {
field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
+ field public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE";
field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e61c39ff2525..773d720d73fb 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -837,6 +837,23 @@ package android.appwidget {
package android.companion {
+ public static final class AssociationInfo.Builder {
+ ctor public AssociationInfo.Builder(int, int, @NonNull String);
+ ctor public AssociationInfo.Builder(@NonNull android.companion.AssociationInfo);
+ method @NonNull public android.companion.AssociationInfo build();
+ method @NonNull public android.companion.AssociationInfo.Builder setAssociatedDevice(@Nullable android.companion.AssociatedDevice);
+ method @NonNull public android.companion.AssociationInfo.Builder setDeviceMacAddress(@Nullable android.net.MacAddress);
+ method @NonNull public android.companion.AssociationInfo.Builder setDeviceProfile(@Nullable String);
+ method @NonNull public android.companion.AssociationInfo.Builder setDisplayName(@Nullable CharSequence);
+ method @NonNull public android.companion.AssociationInfo.Builder setLastTimeConnected(long);
+ method @NonNull public android.companion.AssociationInfo.Builder setNotifyOnDeviceNearby(boolean);
+ method @NonNull public android.companion.AssociationInfo.Builder setRevoked(boolean);
+ method @NonNull public android.companion.AssociationInfo.Builder setSelfManaged(boolean);
+ method @NonNull public android.companion.AssociationInfo.Builder setSystemDataSyncFlags(int);
+ method @NonNull public android.companion.AssociationInfo.Builder setTag(@Nullable String);
+ method @NonNull public android.companion.AssociationInfo.Builder setTimeApproved(long);
+ }
+
public final class CompanionDeviceManager {
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void enableSecureTransport(boolean);
field public static final int MESSAGE_REQUEST_PING = 1669362552; // 0x63807378
@@ -1877,6 +1894,8 @@ package android.media {
public class AudioManager {
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int abandonAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String);
+ method @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") public boolean enterAudioFocusFreezeForTest(@NonNull java.util.List<java.lang.Integer>);
+ method @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") public boolean exitAudioFocusFreezeForTest();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void forceComputeCsdOnAllDevices(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void forceUseFrameworkMel(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull android.media.AudioFormat);
@@ -1884,6 +1903,9 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public float getCsd();
method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFadeOutDurationOnFocusLossMillis(@NonNull android.media.AudioAttributes);
+ method @NonNull @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public java.util.List<java.lang.Integer> getFocusDuckedUidsForTest();
+ method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFocusFadeOutDurationForTest();
+ method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFocusUnmuteDelayAfterFadeOutForTest();
method @Nullable public static android.media.AudioHalVersionInfo getHalVersion();
method public static final int[] getPublicStreamTypes();
method @NonNull public java.util.List<java.lang.Integer> getReportedSurroundFormats();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6cad578b6d7e..bf5b428bc9b1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2900,11 +2900,6 @@ public class Notification implements Parcelable
}
}
- final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
- if (person != null) {
- person.visitUris(visitor);
- }
-
final RemoteInputHistoryItem[] history = extras.getParcelableArray(
Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
RemoteInputHistoryItem.class);
@@ -2916,9 +2911,14 @@ public class Notification implements Parcelable
}
}
}
- }
- if (isStyle(MessagingStyle.class) && extras != null) {
+ // Extras for MessagingStyle. We visit them even if not isStyle(MessagingStyle), since
+ // Notification Listeners might use directly (without the isStyle check).
+ final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
+ if (person != null) {
+ person.visitUris(visitor);
+ }
+
final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES,
Parcelable.class);
if (!ArrayUtils.isEmpty(messages)) {
@@ -2938,9 +2938,8 @@ public class Notification implements Parcelable
}
visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class));
- }
- if (isStyle(CallStyle.class) & extras != null) {
+ // Extras for CallStyle (same reason for visiting without checking isStyle).
Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
if (callPerson != null) {
callPerson.visitUris(visitor);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e57849957f13..fbb97ffea035 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -243,6 +243,7 @@ import android.view.translation.ITranslationManager;
import android.view.translation.TranslationManager;
import android.view.translation.UiTranslationManager;
+import com.android.internal.R;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.ISoundTriggerService;
@@ -871,6 +872,10 @@ public final class SystemServiceRegistry {
PackageManager.FEATURE_COMPANION_DEVICE_SETUP)) {
return null;
}
+ if (!ctx.getResources().getBoolean(R.bool.config_enableVirtualDeviceManager)) {
+ return null;
+ }
+
IVirtualDeviceManager service = IVirtualDeviceManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.VIRTUAL_DEVICE_SERVICE));
return new VirtualDeviceManager(service, ctx.getOuterContext());
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 33b8b03e3258..715edc5161b7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16111,11 +16111,6 @@ public class DevicePolicyManager {
* Called by a profile owner of an organization-owned managed profile to suspend personal
* apps on the device. When personal apps are suspended the device can only be used for calls.
*
- * <p>When personal apps are suspended, an ongoing notification about that is shown to the user.
- * When the user taps the notification, system invokes {@link #ACTION_CHECK_POLICY_COMPLIANCE}
- * in the profile owner package. Profile owner implementation that uses personal apps suspension
- * must handle this intent.
- *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with
* @param suspended Whether personal apps should be suspended.
* @throws IllegalStateException if the profile owner doesn't have an activity that handles
diff --git a/core/java/android/app/search/SearchSession.java b/core/java/android/app/search/SearchSession.java
index 0dbd81ee507d..99b64a05b5e2 100644
--- a/core/java/android/app/search/SearchSession.java
+++ b/core/java/android/app/search/SearchSession.java
@@ -104,7 +104,7 @@ public final class SearchSession implements AutoCloseable {
mInterface = android.app.search.ISearchUiManager.Stub.asInterface(b);
mSessionId = new SearchSessionId(
context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
- // b/175527717 whitelist possible clients of this API
+ // b/175527717 allowlist possible clients of this API
searchContext.setPackageName(context.getPackageName());
try {
mInterface.createSearchSession(searchContext, mSessionId, mToken);
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 7d62c79e7519..083fa0041b26 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -17,7 +17,9 @@ package android.companion;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.net.MacAddress;
import android.os.Parcel;
@@ -41,24 +43,26 @@ public final class AssociationInfo implements Parcelable {
private static final String LAST_TIME_CONNECTED_NONE = "None";
/**
* A unique ID of this Association record.
- * Disclosed to the clients (ie. companion applications) for referring to this record (eg. in
+ * Disclosed to the clients (i.e. companion applications) for referring to this record (e.g. in
* {@code disassociate()} API call).
*/
private final int mId;
-
- private final @UserIdInt int mUserId;
- private final @NonNull String mPackageName;
-
- private final @Nullable MacAddress mDeviceMacAddress;
- private final @Nullable CharSequence mDisplayName;
- private final @Nullable String mDeviceProfile;
- private final @Nullable AssociatedDevice mAssociatedDevice;
-
+ @UserIdInt
+ private final int mUserId;
+ @NonNull
+ private final String mPackageName;
+ @Nullable
+ private final String mTag;
+ @Nullable
+ private final MacAddress mDeviceMacAddress;
+ @Nullable
+ private final CharSequence mDisplayName;
+ @Nullable
+ private final String mDeviceProfile;
+ @Nullable
+ private final AssociatedDevice mAssociatedDevice;
private final boolean mSelfManaged;
private final boolean mNotifyOnDeviceNearby;
- private final int mSystemDataSyncFlags;
- private final String mTag;
-
/**
* Indicates that the association has been revoked (removed), but we keep the association
* record for final clean up (e.g. removing the app from the list of the role holders).
@@ -72,6 +76,7 @@ public final class AssociationInfo implements Parcelable {
* Default value is Long.MAX_VALUE.
*/
private final long mLastTimeConnectedMs;
+ private final int mSystemDataSyncFlags;
/**
* Creates a new Association.
@@ -93,16 +98,13 @@ public final class AssociationInfo implements Parcelable {
}
mId = id;
-
mUserId = userId;
mPackageName = packageName;
-
mDeviceMacAddress = macAddress;
mDisplayName = displayName;
mTag = tag;
mDeviceProfile = deviceProfile;
mAssociatedDevice = associatedDevice;
-
mSelfManaged = selfManaged;
mNotifyOnDeviceNearby = notifyOnDeviceNearby;
mRevoked = revoked;
@@ -119,18 +121,11 @@ public final class AssociationInfo implements Parcelable {
}
/**
- * @return the tag of this association.
- * @see CompanionDeviceManager#setAssociationTag(int, String)
- */
- public @Nullable String getTag() {
- return mTag;
- }
-
- /**
* @return the ID of the user who "owns" this association.
* @hide
*/
- public @UserIdInt int getUserId() {
+ @UserIdInt
+ public int getUserId() {
return mUserId;
}
@@ -139,19 +134,31 @@ public final class AssociationInfo implements Parcelable {
* @hide
*/
@SystemApi
- public @NonNull String getPackageName() {
+ @NonNull
+ public String getPackageName() {
return mPackageName;
}
/**
+ * @return the tag of this association.
+ * @see CompanionDeviceManager#setAssociationTag(int, String)
+ */
+ @Nullable
+ public String getTag() {
+ return mTag;
+ }
+
+ /**
* @return the MAC address of the device.
*/
- public @Nullable MacAddress getDeviceMacAddress() {
+ @Nullable
+ public MacAddress getDeviceMacAddress() {
return mDeviceMacAddress;
}
/** @hide */
- public @Nullable String getDeviceMacAddressAsString() {
+ @Nullable
+ public String getDeviceMacAddressAsString() {
return mDeviceMacAddress != null ? mDeviceMacAddress.toString().toUpperCase() : null;
}
@@ -161,7 +168,8 @@ public final class AssociationInfo implements Parcelable {
*
* @see AssociationRequest.Builder#setDisplayName(CharSequence)
*/
- public @Nullable CharSequence getDisplayName() {
+ @Nullable
+ public CharSequence getDisplayName() {
return mDisplayName;
}
@@ -170,7 +178,8 @@ public final class AssociationInfo implements Parcelable {
* association, or {@code null} if no specific profile was used.
* @see AssociationRequest.Builder#setDeviceProfile(String)
*/
- public @Nullable String getDeviceProfile() {
+ @Nullable
+ public String getDeviceProfile() {
return mDeviceProfile;
}
@@ -187,7 +196,8 @@ public final class AssociationInfo implements Parcelable {
* @return the companion device that was associated, or {@code null} if the device is
* self-managed or this association info was retrieved from persistent storage.
*/
- public @Nullable AssociatedDevice getAssociatedDevice() {
+ @Nullable
+ public AssociatedDevice getAssociatedDevice() {
return mAssociatedDevice;
}
@@ -228,14 +238,14 @@ public final class AssociationInfo implements Parcelable {
* @return the last time self reported disconnected for selfManaged only.
* @hide
*/
- public Long getLastTimeConnectedMs() {
+ public long getLastTimeConnectedMs() {
return mLastTimeConnectedMs;
}
/**
* @return Enabled system data sync flags set via
- * {@link CompanionDeviceManager#enableSystemDataSync(int, int)} and
- * {@link CompanionDeviceManager#disableSystemDataSync(int, int)}.
+ * {@link CompanionDeviceManager#enableSystemDataSyncForTypes(int, int)} (int, int)} and
+ * {@link CompanionDeviceManager#disableSystemDataSyncForTypes(int, int)} (int, int)}.
* Or by default all flags are 1 (enabled).
*/
public int getSystemDataSyncFlags() {
@@ -279,7 +289,8 @@ public final class AssociationInfo implements Parcelable {
}
/** @hide */
- public @NonNull String toShortString() {
+ @NonNull
+ public String toShortString() {
final StringBuilder sb = new StringBuilder();
sb.append("id=").append(mId);
if (mDeviceMacAddress != null) {
@@ -350,16 +361,13 @@ public final class AssociationInfo implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mId);
-
dest.writeInt(mUserId);
dest.writeString(mPackageName);
dest.writeString(mTag);
-
dest.writeTypedObject(mDeviceMacAddress, 0);
dest.writeCharSequence(mDisplayName);
dest.writeString(mDeviceProfile);
dest.writeTypedObject(mAssociatedDevice, 0);
-
dest.writeBoolean(mSelfManaged);
dest.writeBoolean(mNotifyOnDeviceNearby);
dest.writeBoolean(mRevoked);
@@ -370,16 +378,13 @@ public final class AssociationInfo implements Parcelable {
private AssociationInfo(@NonNull Parcel in) {
mId = in.readInt();
-
mUserId = in.readInt();
mPackageName = in.readString();
mTag = in.readString();
-
mDeviceMacAddress = in.readTypedObject(MacAddress.CREATOR);
mDisplayName = in.readCharSequence();
mDeviceProfile = in.readString();
mAssociatedDevice = in.readTypedObject(AssociatedDevice.CREATOR);
-
mSelfManaged = in.readBoolean();
mNotifyOnDeviceNearby = in.readBoolean();
mRevoked = in.readBoolean();
@@ -403,139 +408,182 @@ public final class AssociationInfo implements Parcelable {
};
/**
- * Use this method to obtain a builder that you can use to create a copy of the
- * given {@link AssociationInfo} with modified values of {@code mLastTimeConnected}
- * or {@code mNotifyOnDeviceNearby}.
- * <p>
- * Note that you <b>must</b> call either {@link Builder#setLastTimeConnected(long)
- * setLastTimeConnected} or {@link Builder#setNotifyOnDeviceNearby(boolean)
- * setNotifyOnDeviceNearby} before you will be able to call {@link Builder#build() build}.
- *
- * This is ensured statically at compile time.
+ * Builder for {@link AssociationInfo}
*
* @hide
*/
- @NonNull
- public static NonActionableBuilder builder(@NonNull AssociationInfo info) {
- return new Builder(info);
- }
-
- /** @hide */
- public static final class Builder implements NonActionableBuilder {
- @NonNull
- private final AssociationInfo mOriginalInfo;
+ @TestApi
+ public static final class Builder {
+ private final int mId;
+ private final int mUserId;
+ private final String mPackageName;
+ private String mTag;
+ private MacAddress mDeviceMacAddress;
+ private CharSequence mDisplayName;
+ private String mDeviceProfile;
+ private AssociatedDevice mAssociatedDevice;
+ private boolean mSelfManaged;
private boolean mNotifyOnDeviceNearby;
private boolean mRevoked;
+ private long mTimeApprovedMs;
private long mLastTimeConnectedMs;
private int mSystemDataSyncFlags;
- private String mTag;
- private Builder(@NonNull AssociationInfo info) {
- mOriginalInfo = info;
+ /** @hide */
+ @TestApi
+ public Builder(int id, int userId, @NonNull String packageName) {
+ mId = id;
+ mUserId = userId;
+ mPackageName = packageName;
+ }
+
+ /** @hide */
+ @TestApi
+ public Builder(@NonNull AssociationInfo info) {
+ mId = info.mId;
+ mUserId = info.mUserId;
+ mPackageName = info.mPackageName;
mTag = info.mTag;
+ mDeviceMacAddress = info.mDeviceMacAddress;
+ mDisplayName = info.mDisplayName;
+ mDeviceProfile = info.mDeviceProfile;
+ mAssociatedDevice = info.mAssociatedDevice;
+ mSelfManaged = info.mSelfManaged;
mNotifyOnDeviceNearby = info.mNotifyOnDeviceNearby;
mRevoked = info.mRevoked;
+ mTimeApprovedMs = info.mTimeApprovedMs;
mLastTimeConnectedMs = info.mLastTimeConnectedMs;
mSystemDataSyncFlags = info.mSystemDataSyncFlags;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
- public Builder setLastTimeConnected(long lastTimeConnectedMs) {
- if (lastTimeConnectedMs < 0) {
- throw new IllegalArgumentException(
- "lastTimeConnectedMs must not be negative! (Given " + lastTimeConnectedMs
- + " )");
- }
- mLastTimeConnectedMs = lastTimeConnectedMs;
+ public Builder setTag(@Nullable String tag) {
+ mTag = tag;
return this;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
- public Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby) {
- mNotifyOnDeviceNearby = notifyOnDeviceNearby;
+ public Builder setDeviceMacAddress(@Nullable MacAddress deviceMacAddress) {
+ mDeviceMacAddress = deviceMacAddress;
return this;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
- public Builder setRevoked(boolean revoked) {
- mRevoked = revoked;
+ public Builder setDisplayName(@Nullable CharSequence displayName) {
+ mDisplayName = displayName;
return this;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
- public Builder setSystemDataSyncFlags(int flags) {
- mSystemDataSyncFlags = flags;
+ public Builder setDeviceProfile(@Nullable String deviceProfile) {
+ mDeviceProfile = deviceProfile;
return this;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
- public Builder setTag(String tag) {
- mTag = tag;
+ public Builder setAssociatedDevice(@Nullable AssociatedDevice associatedDevice) {
+ mAssociatedDevice = associatedDevice;
return this;
}
/** @hide */
+ @TestApi
@NonNull
- public AssociationInfo build() {
- return new AssociationInfo(
- mOriginalInfo.mId,
- mOriginalInfo.mUserId,
- mOriginalInfo.mPackageName,
- mTag,
- mOriginalInfo.mDeviceMacAddress,
- mOriginalInfo.mDisplayName,
- mOriginalInfo.mDeviceProfile,
- mOriginalInfo.mAssociatedDevice,
- mOriginalInfo.mSelfManaged,
- mNotifyOnDeviceNearby,
- mRevoked,
- mOriginalInfo.mTimeApprovedMs,
- mLastTimeConnectedMs,
- mSystemDataSyncFlags
- );
+ public Builder setSelfManaged(boolean selfManaged) {
+ mSelfManaged = selfManaged;
+ return this;
}
- }
- /**
- * This interface is returned from the
- * {@link AssociationInfo#builder(android.companion.AssociationInfo) builder} entry point
- * to indicate that this builder is not yet in a state that can produce a meaningful
- * {@link AssociationInfo} object that is different from the one originally passed in.
- *
- * <p>
- * Only by calling one of the setter methods is this builder turned into one where calling
- * {@link Builder#build() build()} makes sense.
- *
- * @hide
- */
- public interface NonActionableBuilder {
/** @hide */
+ @TestApi
@NonNull
- Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby);
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby) {
+ mNotifyOnDeviceNearby = notifyOnDeviceNearby;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setRevoked(boolean revoked) {
+ mRevoked = revoked;
+ return this;
+ }
/** @hide */
+ @TestApi
@NonNull
- Builder setLastTimeConnected(long lastTimeConnectedMs);
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setTimeApproved(long timeApprovedMs) {
+ if (timeApprovedMs < 0) {
+ throw new IllegalArgumentException("timeApprovedMs must be positive. Was given ("
+ + timeApprovedMs + ")");
+ }
+ mTimeApprovedMs = timeApprovedMs;
+ return this;
+ }
/** @hide */
+ @TestApi
@NonNull
- Builder setRevoked(boolean revoked);
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setLastTimeConnected(long lastTimeConnectedMs) {
+ if (lastTimeConnectedMs < 0) {
+ throw new IllegalArgumentException(
+ "lastTimeConnectedMs must not be negative! (Given " + lastTimeConnectedMs
+ + " )");
+ }
+ mLastTimeConnectedMs = lastTimeConnectedMs;
+ return this;
+ }
/** @hide */
+ @TestApi
@NonNull
- Builder setSystemDataSyncFlags(int flags);
+ public Builder setSystemDataSyncFlags(int flags) {
+ mSystemDataSyncFlags = flags;
+ return this;
+ }
/** @hide */
- Builder setTag(String tag);
+ @TestApi
+ @NonNull
+ public AssociationInfo build() {
+ if (mId <= 0) {
+ throw new IllegalArgumentException("Association ID should be greater than 0");
+ }
+ if (mDeviceMacAddress == null && mDisplayName == null) {
+ throw new IllegalArgumentException("MAC address and the display name must NOT be "
+ + "null at the same time");
+ }
+ return new AssociationInfo(
+ mId,
+ mUserId,
+ mPackageName,
+ mTag,
+ mDeviceMacAddress,
+ mDisplayName,
+ mDeviceProfile,
+ mAssociatedDevice,
+ mSelfManaged,
+ mNotifyOnDeviceNearby,
+ mRevoked,
+ mTimeApprovedMs,
+ mLastTimeConnectedMs,
+ mSystemDataSyncFlags
+ );
+ }
}
}
diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java
index e931fe8526f1..1ef3d273fcb8 100644
--- a/core/java/android/content/res/Element.java
+++ b/core/java/android/content/res/Element.java
@@ -42,7 +42,7 @@ public class Element {
public static final int MAX_ATTR_LEN_PATH = 4000;
public static final int MAX_ATTR_LEN_DATA_VALUE = 4000;
- private static final String BAD_COMPONENT_NAME_CHARS = ";,[](){}:?-%^*|/\\";
+ private static final String BAD_COMPONENT_NAME_CHARS = ";,[](){}:?%^*|/\\";
private static final String TAG = "PackageParsing";
protected static final String TAG_ACTION = "action";
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 5b80e6a0b188..746f2f23fd5c 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -44,10 +44,12 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Printer;
+
import com.android.internal.util.Preconditions;
import dalvik.annotation.optimization.NeverCompile;
import dalvik.system.CloseGuard;
+
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
@@ -1473,8 +1475,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* SQL WHERE clause (excluding the WHERE itself). Passing null
* will return all rows for the given table.
* @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in order that they
+ * replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
+ * If selection is null or does not contain ?s then selectionArgs
+ * may be null.
* @param groupBy A filter declaring how to group rows, formatted as an SQL
* GROUP BY clause (excluding the GROUP BY itself). Passing null
* will cause the rows to not be grouped.
@@ -1492,9 +1496,11 @@ public final class SQLiteDatabase extends SQLiteClosable {
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see Cursor
*/
- public Cursor query(boolean distinct, String table, String[] columns,
- String selection, String[] selectionArgs, String groupBy,
- String having, String orderBy, String limit) {
+ @NonNull
+ public Cursor query(boolean distinct, @NonNull String table,
+ @Nullable String[] columns, @Nullable String selection,
+ @Nullable String[] selectionArgs, @Nullable String groupBy, @Nullable String having,
+ @Nullable String orderBy, @Nullable String limit) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
groupBy, having, orderBy, limit, null);
}
@@ -1511,8 +1517,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* SQL WHERE clause (excluding the WHERE itself). Passing null
* will return all rows for the given table.
* @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in order that they
+ * replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
+ * If selection is null or does not contain ?s then selectionArgs
+ * may be null.
* @param groupBy A filter declaring how to group rows, formatted as an SQL
* GROUP BY clause (excluding the GROUP BY itself). Passing null
* will cause the rows to not be grouped.
@@ -1533,9 +1541,12 @@ public final class SQLiteDatabase extends SQLiteClosable {
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see Cursor
*/
- public Cursor query(boolean distinct, String table, String[] columns,
- String selection, String[] selectionArgs, String groupBy,
- String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
+ @NonNull
+ public Cursor query(boolean distinct, @NonNull String table,
+ @Nullable String[] columns, @Nullable String selection,
+ @Nullable String[] selectionArgs, @Nullable String groupBy, @Nullable String having,
+ @Nullable String orderBy, @Nullable String limit,
+ @Nullable CancellationSignal cancellationSignal) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
groupBy, having, orderBy, limit, cancellationSignal);
}
@@ -1553,8 +1564,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* SQL WHERE clause (excluding the WHERE itself). Passing null
* will return all rows for the given table.
* @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in order that they
+ * replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
+ * If selection is null or does not contain ?s then selectionArgs
+ * may be null.
* @param groupBy A filter declaring how to group rows, formatted as an SQL
* GROUP BY clause (excluding the GROUP BY itself). Passing null
* will cause the rows to not be grouped.
@@ -1572,10 +1585,12 @@ public final class SQLiteDatabase extends SQLiteClosable {
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see Cursor
*/
- public Cursor queryWithFactory(CursorFactory cursorFactory,
- boolean distinct, String table, String[] columns,
- String selection, String[] selectionArgs, String groupBy,
- String having, String orderBy, String limit) {
+ @SuppressLint("SamShouldBeLast")
+ @NonNull
+ public Cursor queryWithFactory(@Nullable CursorFactory cursorFactory,
+ boolean distinct, @NonNull String table, @Nullable String[] columns,
+ @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String groupBy,
+ @Nullable String having, @Nullable String orderBy, @Nullable String limit) {
return queryWithFactory(cursorFactory, distinct, table, columns, selection,
selectionArgs, groupBy, having, orderBy, limit, null);
}
@@ -1593,8 +1608,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* SQL WHERE clause (excluding the WHERE itself). Passing null
* will return all rows for the given table.
* @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in order that they
+ * replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
+ * If selection is null or does not contain ?s then selectionArgs
+ * may be null.
* @param groupBy A filter declaring how to group rows, formatted as an SQL
* GROUP BY clause (excluding the GROUP BY itself). Passing null
* will cause the rows to not be grouped.
@@ -1615,10 +1632,13 @@ public final class SQLiteDatabase extends SQLiteClosable {
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see Cursor
*/
- public Cursor queryWithFactory(CursorFactory cursorFactory,
- boolean distinct, String table, String[] columns,
- String selection, String[] selectionArgs, String groupBy,
- String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
+ @SuppressLint("SamShouldBeLast")
+ @NonNull
+ public Cursor queryWithFactory(@Nullable CursorFactory cursorFactory,
+ boolean distinct, @NonNull String table, @Nullable String[] columns,
+ @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String groupBy,
+ @Nullable String having, @Nullable String orderBy, @Nullable String limit,
+ @Nullable CancellationSignal cancellationSignal) {
acquireReference();
try {
String sql = SQLiteQueryBuilder.buildQueryString(
@@ -1642,8 +1662,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* SQL WHERE clause (excluding the WHERE itself). Passing null
* will return all rows for the given table.
* @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in order that they
+ * replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
+ * If selection is null or does not contain ?s then selectionArgs
+ * may be null.
* @param groupBy A filter declaring how to group rows, formatted as an SQL
* GROUP BY clause (excluding the GROUP BY itself). Passing null
* will cause the rows to not be grouped.
@@ -1659,9 +1681,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see Cursor
*/
- public Cursor query(String table, String[] columns, String selection,
- String[] selectionArgs, String groupBy, String having,
- String orderBy) {
+ @NonNull
+ public Cursor query(@NonNull String table, @Nullable String[] columns,
+ @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String groupBy,
+ @Nullable String having, @Nullable String orderBy) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, null /* limit */);
@@ -1678,8 +1701,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* SQL WHERE clause (excluding the WHERE itself). Passing null
* will return all rows for the given table.
* @param selectionArgs You may include ?s in selection, which will be
- * replaced by the values from selectionArgs, in order that they
+ * replaced by the values from selectionArgs, in the order that they
* appear in the selection. The values will be bound as Strings.
+ * If selection is null or does not contain ?s then selectionArgs
+ * may be null.
* @param groupBy A filter declaring how to group rows, formatted as an SQL
* GROUP BY clause (excluding the GROUP BY itself). Passing null
* will cause the rows to not be grouped.
@@ -1697,9 +1722,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see Cursor
*/
- public Cursor query(String table, String[] columns, String selection,
- String[] selectionArgs, String groupBy, String having,
- String orderBy, String limit) {
+ @NonNull
+ public Cursor query(@NonNull String table, @Nullable String[] columns,
+ @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String groupBy,
+ @Nullable String having, @Nullable String orderBy, @Nullable String limit) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, limit);
@@ -1711,11 +1737,13 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @param sql the SQL query. The SQL string must not be ; terminated
* @param selectionArgs You may include ?s in where clause in the query,
* which will be replaced by the values from selectionArgs. The
- * values will be bound as Strings.
+ * values will be bound as Strings. If selection is null or does not contain ?s then
+ * selectionArgs may be null.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
*/
- public Cursor rawQuery(String sql, String[] selectionArgs) {
+ @NonNull
+ public Cursor rawQuery(@NonNull String sql, @Nullable String[] selectionArgs) {
return rawQueryWithFactory(null, sql, selectionArgs, null, null);
}
@@ -1725,15 +1753,17 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @param sql the SQL query. The SQL string must not be ; terminated
* @param selectionArgs You may include ?s in where clause in the query,
* which will be replaced by the values from selectionArgs. The
- * values will be bound as Strings.
+ * values will be bound as Strings. If selection is null or does not contain ?s then
+ * selectionArgs may be null.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
*/
- public Cursor rawQuery(String sql, String[] selectionArgs,
- CancellationSignal cancellationSignal) {
+ @NonNull
+ public Cursor rawQuery(@NonNull String sql, @Nullable String[] selectionArgs,
+ @Nullable CancellationSignal cancellationSignal) {
return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
}
@@ -1744,14 +1774,16 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @param sql the SQL query. The SQL string must not be ; terminated
* @param selectionArgs You may include ?s in where clause in the query,
* which will be replaced by the values from selectionArgs. The
- * values will be bound as Strings.
+ * values will be bound as Strings. If selection is null or does not contain ?s then
+ * selectionArgs may be null.
* @param editTable the name of the first table, which is editable
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
*/
+ @NonNull
public Cursor rawQueryWithFactory(
- CursorFactory cursorFactory, String sql, String[] selectionArgs,
- String editTable) {
+ @Nullable CursorFactory cursorFactory, @NonNull String sql,
+ @Nullable String[] selectionArgs, @NonNull String editTable) {
return rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable, null);
}
@@ -1762,7 +1794,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @param sql the SQL query. The SQL string must not be ; terminated
* @param selectionArgs You may include ?s in where clause in the query,
* which will be replaced by the values from selectionArgs. The
- * values will be bound as Strings.
+ * values will be bound as Strings. If selection is null or does not contain ?s then
+ * selectionArgs may be null.
* @param editTable the name of the first table, which is editable
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
@@ -1770,9 +1803,11 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
*/
+ @NonNull
public Cursor rawQueryWithFactory(
- CursorFactory cursorFactory, String sql, String[] selectionArgs,
- String editTable, CancellationSignal cancellationSignal) {
+ @Nullable CursorFactory cursorFactory, @NonNull String sql,
+ @Nullable String[] selectionArgs, @NonNull String editTable,
+ @Nullable CancellationSignal cancellationSignal) {
acquireReference();
try {
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
@@ -1800,7 +1835,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* column values
* @return the row ID of the newly inserted row, or -1 if an error occurred
*/
- public long insert(String table, String nullColumnHack, ContentValues values) {
+ public long insert(@NonNull String table, @Nullable String nullColumnHack,
+ @Nullable ContentValues values) {
try {
return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
} catch (SQLException e) {
@@ -1826,8 +1862,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @throws SQLException
* @return the row ID of the newly inserted row, or -1 if an error occurred
*/
- public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
- throws SQLException {
+ public long insertOrThrow(@NonNull String table, @Nullable String nullColumnHack,
+ @Nullable ContentValues values) throws SQLException {
return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
}
@@ -1847,7 +1883,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* the row. The keys should be the column names and the values the column values.
* @return the row ID of the newly inserted row, or -1 if an error occurred
*/
- public long replace(String table, String nullColumnHack, ContentValues initialValues) {
+ public long replace(@NonNull String table, @Nullable String nullColumnHack,
+ @Nullable ContentValues initialValues) {
try {
return insertWithOnConflict(table, nullColumnHack, initialValues,
CONFLICT_REPLACE);
@@ -1874,8 +1911,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @throws SQLException
* @return the row ID of the newly inserted row, or -1 if an error occurred
*/
- public long replaceOrThrow(String table, String nullColumnHack,
- ContentValues initialValues) throws SQLException {
+ public long replaceOrThrow(@NonNull String table, @Nullable String nullColumnHack,
+ @Nullable ContentValues initialValues) throws SQLException {
return insertWithOnConflict(table, nullColumnHack, initialValues,
CONFLICT_REPLACE);
}
@@ -1899,8 +1936,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* input parameter <code>conflictAlgorithm</code> = {@link #CONFLICT_IGNORE}
* or an error occurred.
*/
- public long insertWithOnConflict(String table, String nullColumnHack,
- ContentValues initialValues, int conflictAlgorithm) {
+ public long insertWithOnConflict(@NonNull String table, @Nullable String nullColumnHack,
+ @Nullable ContentValues initialValues, int conflictAlgorithm) {
acquireReference();
try {
StringBuilder sql = new StringBuilder();
@@ -1950,12 +1987,14 @@ public final class SQLiteDatabase extends SQLiteClosable {
* Passing null will delete all rows.
* @param whereArgs You may include ?s in the where clause, which
* will be replaced by the values from whereArgs. The values
- * will be bound as Strings.
+ * will be bound as Strings. If whereClause is null or does not
+ * contain ?s then whereArgs may be null.
* @return the number of rows affected if a whereClause is passed in, 0
* otherwise. To remove all rows and get a count pass "1" as the
* whereClause.
*/
- public int delete(String table, String whereClause, String[] whereArgs) {
+ public int delete(@NonNull String table, @Nullable String whereClause,
+ @Nullable String[] whereArgs) {
acquireReference();
try {
SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table +
@@ -1980,10 +2019,12 @@ public final class SQLiteDatabase extends SQLiteClosable {
* Passing null will update all rows.
* @param whereArgs You may include ?s in the where clause, which
* will be replaced by the values from whereArgs. The values
- * will be bound as Strings.
+ * will be bound as Strings. If whereClause is null or does not
+ * contain ?s then whereArgs may be null.
* @return the number of rows affected
*/
- public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
+ public int update(@NonNull String table, @Nullable ContentValues values,
+ @Nullable String whereClause, @Nullable String[] whereArgs) {
return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
}
@@ -1997,12 +2038,13 @@ public final class SQLiteDatabase extends SQLiteClosable {
* Passing null will update all rows.
* @param whereArgs You may include ?s in the where clause, which
* will be replaced by the values from whereArgs. The values
- * will be bound as Strings.
+ * will be bound as Strings. If whereClause is null or does not
+ * contain ?s then whereArgs may be null.
* @param conflictAlgorithm for update conflict resolver
* @return the number of rows affected
*/
- public int updateWithOnConflict(String table, ContentValues values,
- String whereClause, String[] whereArgs, int conflictAlgorithm) {
+ public int updateWithOnConflict(@NonNull String table, @Nullable ContentValues values,
+ @Nullable String whereClause, @Nullable String[] whereArgs, int conflictAlgorithm) {
if (values == null || values.isEmpty()) {
throw new IllegalArgumentException("Empty values");
}
@@ -2125,7 +2167,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
* @throws SQLException if the SQL string is invalid
*/
- public void execSQL(String sql, Object[] bindArgs) throws SQLException {
+ public void execSQL(@NonNull String sql, @NonNull Object[] bindArgs)
+ throws SQLException {
if (bindArgs == null) {
throw new IllegalArgumentException("Empty bindArgs");
}
@@ -2133,7 +2176,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
}
/** {@hide} */
- public int executeSql(String sql, Object[] bindArgs) throws SQLException {
+ public int executeSql(@NonNull String sql, @NonNull Object[] bindArgs)
+ throws SQLException {
acquireReference();
try {
final int statementType = DatabaseUtils.getSqlStatementType(sql);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index ccc39b6080d7..039644387715 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -41,11 +41,6 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RSIllegalArgumentException;
-import android.renderscript.RenderScript;
-import android.renderscript.Type;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
@@ -1007,132 +1002,6 @@ public class Camera {
private native final void _addCallbackBuffer(
byte[] callbackBuffer, int msgType);
- /**
- * <p>Create a {@link android.renderscript RenderScript}
- * {@link android.renderscript.Allocation Allocation} to use as a
- * destination of preview callback frames. Use
- * {@link #setPreviewCallbackAllocation setPreviewCallbackAllocation} to use
- * the created Allocation as a destination for camera preview frames.</p>
- *
- * <p>The Allocation will be created with a YUV type, and its contents must
- * be accessed within Renderscript with the {@code rsGetElementAtYuv_*}
- * accessor methods. Its size will be based on the current
- * {@link Parameters#getPreviewSize preview size} configured for this
- * camera.</p>
- *
- * @param rs the RenderScript context for this Allocation.
- * @param usage additional usage flags to set for the Allocation. The usage
- * flag {@link android.renderscript.Allocation#USAGE_IO_INPUT} will always
- * be set on the created Allocation, but additional flags may be provided
- * here.
- * @return a new YUV-type Allocation with dimensions equal to the current
- * preview size.
- * @throws RSIllegalArgumentException if the usage flags are not compatible
- * with an YUV Allocation.
- * @see #setPreviewCallbackAllocation
- * @hide
- */
- public final Allocation createPreviewAllocation(RenderScript rs, int usage)
- throws RSIllegalArgumentException {
- Parameters p = getParameters();
- Size previewSize = p.getPreviewSize();
- Type.Builder yuvBuilder = new Type.Builder(rs,
- Element.createPixel(rs,
- Element.DataType.UNSIGNED_8,
- Element.DataKind.PIXEL_YUV));
- // Use YV12 for wide compatibility. Changing this requires also
- // adjusting camera service's format selection.
- yuvBuilder.setYuvFormat(ImageFormat.YV12);
- yuvBuilder.setX(previewSize.width);
- yuvBuilder.setY(previewSize.height);
-
- Allocation a = Allocation.createTyped(rs, yuvBuilder.create(),
- usage | Allocation.USAGE_IO_INPUT);
-
- return a;
- }
-
- /**
- * <p>Set an {@link android.renderscript.Allocation Allocation} as the
- * target of preview callback data. Use this method for efficient processing
- * of camera preview data with RenderScript. The Allocation must be created
- * with the {@link #createPreviewAllocation createPreviewAllocation }
- * method.</p>
- *
- * <p>Setting a preview allocation will disable any active preview callbacks
- * set by {@link #setPreviewCallback setPreviewCallback} or
- * {@link #setPreviewCallbackWithBuffer setPreviewCallbackWithBuffer}, and
- * vice versa. Using a preview allocation still requires an active standard
- * preview target to be set, either with
- * {@link #setPreviewTexture setPreviewTexture} or
- * {@link #setPreviewDisplay setPreviewDisplay}.</p>
- *
- * <p>To be notified when new frames are available to the Allocation, use
- * {@link android.renderscript.Allocation#setIoInputNotificationHandler Allocation.setIoInputNotificationHandler}. To
- * update the frame currently accessible from the Allocation to the latest
- * preview frame, call
- * {@link android.renderscript.Allocation#ioReceive Allocation.ioReceive}.</p>
- *
- * <p>To disable preview into the Allocation, call this method with a
- * {@code null} parameter.</p>
- *
- * <p>Once a preview allocation is set, the preview size set by
- * {@link Parameters#setPreviewSize setPreviewSize} cannot be changed. If
- * you wish to change the preview size, first remove the preview allocation
- * by calling {@code setPreviewCallbackAllocation(null)}, then change the
- * preview size, create a new preview Allocation with
- * {@link #createPreviewAllocation createPreviewAllocation}, and set it as
- * the new preview callback allocation target.</p>
- *
- * <p>If you are using the preview data to create video or still images,
- * strongly consider using {@link android.media.MediaActionSound} to
- * properly indicate image capture or recording start/stop to the user.</p>
- *
- * @param previewAllocation the allocation to use as destination for preview
- * @throws IOException if configuring the camera to use the Allocation for
- * preview fails.
- * @throws IllegalArgumentException if the Allocation's dimensions or other
- * parameters don't meet the requirements.
- * @see #createPreviewAllocation
- * @see #setPreviewCallback
- * @see #setPreviewCallbackWithBuffer
- * @hide
- */
- public final void setPreviewCallbackAllocation(Allocation previewAllocation)
- throws IOException {
- Surface previewSurface = null;
- if (previewAllocation != null) {
- Parameters p = getParameters();
- Size previewSize = p.getPreviewSize();
- if (previewSize.width != previewAllocation.getType().getX() ||
- previewSize.height != previewAllocation.getType().getY()) {
- throw new IllegalArgumentException(
- "Allocation dimensions don't match preview dimensions: " +
- "Allocation is " +
- previewAllocation.getType().getX() +
- ", " +
- previewAllocation.getType().getY() +
- ". Preview is " + previewSize.width + ", " +
- previewSize.height);
- }
- if ((previewAllocation.getUsage() &
- Allocation.USAGE_IO_INPUT) == 0) {
- throw new IllegalArgumentException(
- "Allocation usage does not include USAGE_IO_INPUT");
- }
- if (previewAllocation.getType().getElement().getDataKind() !=
- Element.DataKind.PIXEL_YUV) {
- throw new IllegalArgumentException(
- "Allocation is not of a YUV type");
- }
- previewSurface = previewAllocation.getSurface();
- mUsingPreviewAllocation = true;
- } else {
- mUsingPreviewAllocation = false;
- }
- setPreviewCallbackSurface(previewSurface);
- }
-
private native final void setPreviewCallbackSurface(Surface s);
private class EventHandler extends Handler
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 912e8df6bdc7..af448f0c4917 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -466,6 +466,19 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
// LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java)
/**
+ * Set if emergency call button should show, for example if biometrics are
+ * required to access the dialer app
+ * @param showEmergencyCallButton if true, shows emergency call button
+ * @return This builder.
+ * @hide
+ */
+ @NonNull
+ public Builder setShowEmergencyCallButton(boolean showEmergencyCallButton) {
+ mPromptInfo.setShowEmergencyCallButton(showEmergencyCallButton);
+ return this;
+ }
+
+ /**
* Creates a {@link BiometricPrompt}.
*
* @return An instance of {@link BiometricPrompt}.
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index e27507874167..24cfd1641410 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -48,6 +48,7 @@ public class PromptInfo implements Parcelable {
private boolean mAllowBackgroundAuthentication;
private boolean mIgnoreEnrollmentState;
private boolean mIsForLegacyFingerprintManager = false;
+ private boolean mShowEmergencyCallButton = false;
public PromptInfo() {
@@ -72,6 +73,7 @@ public class PromptInfo implements Parcelable {
mAllowBackgroundAuthentication = in.readBoolean();
mIgnoreEnrollmentState = in.readBoolean();
mIsForLegacyFingerprintManager = in.readBoolean();
+ mShowEmergencyCallButton = in.readBoolean();
}
public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -111,6 +113,7 @@ public class PromptInfo implements Parcelable {
dest.writeBoolean(mAllowBackgroundAuthentication);
dest.writeBoolean(mIgnoreEnrollmentState);
dest.writeBoolean(mIsForLegacyFingerprintManager);
+ dest.writeBoolean(mShowEmergencyCallButton);
}
// LINT.IfChange
@@ -228,6 +231,10 @@ public class PromptInfo implements Parcelable {
mAllowedSensorIds.add(sensorId);
}
+ public void setShowEmergencyCallButton(boolean showEmergencyCallButton) {
+ mShowEmergencyCallButton = showEmergencyCallButton;
+ }
+
// Getters
public CharSequence getTitle() {
@@ -309,4 +316,8 @@ public class PromptInfo implements Parcelable {
public boolean isForLegacyFingerprintManager() {
return mIsForLegacyFingerprintManager;
}
+
+ public boolean isShowEmergencyCallButton() {
+ return mShowEmergencyCallButton;
+ }
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 0e45787c1340..082a3361be4e 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -541,14 +541,6 @@ public abstract class CameraDevice implements AutoCloseable {
* or configuring it to use one of the supported
* {@link android.media.CamcorderProfile CamcorderProfiles}.</li>
*
- * <li>For efficient YUV processing with {@link android.renderscript}:
- * Create a RenderScript
- * {@link android.renderscript.Allocation Allocation} with a supported YUV
- * type, the IO_INPUT flag, and one of the sizes returned by
- * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(Allocation.class)},
- * Then obtain the Surface with
- * {@link android.renderscript.Allocation#getSurface}.</li>
- *
* <li>For access to RAW, uncompressed YUV, or compressed JPEG data in the application: Create an
* {@link android.media.ImageReader} object with one of the supported output formats given by
* {@link StreamConfigurationMap#getOutputFormats()}, setting its size to one of the
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 6baf91d720c3..ea951a55bfca 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -236,9 +236,10 @@ public final class CameraExtensionCharacteristics {
private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
new CameraExtensionManagerGlobal();
private final Object mLock = new Object();
- private final int PROXY_SERVICE_DELAY_MS = 1000;
+ private final int PROXY_SERVICE_DELAY_MS = 2000;
private InitializerFuture mInitFuture = null;
private ServiceConnection mConnection = null;
+ private int mConnectionCount = 0;
private ICameraExtensionsProxyService mProxy = null;
private boolean mSupportsAdvancedExtensions = false;
@@ -249,6 +250,15 @@ public final class CameraExtensionCharacteristics {
return GLOBAL_CAMERA_MANAGER;
}
+ private void releaseProxyConnectionLocked(Context ctx) {
+ if (mConnection != null ) {
+ ctx.unbindService(mConnection);
+ mConnection = null;
+ mProxy = null;
+ mConnectionCount = 0;
+ }
+ }
+
private void connectToProxyLocked(Context ctx) {
if (mConnection == null) {
Intent intent = new Intent();
@@ -270,7 +280,6 @@ public final class CameraExtensionCharacteristics {
mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName component) {
- mInitFuture.setStatus(false);
mConnection = null;
mProxy = null;
}
@@ -348,23 +357,32 @@ public final class CameraExtensionCharacteristics {
public boolean registerClient(Context ctx, IBinder token) {
synchronized (mLock) {
+ boolean ret = false;
connectToProxyLocked(ctx);
if (mProxy == null) {
return false;
}
+ mConnectionCount++;
try {
- return mProxy.registerClient(token);
+ ret = mProxy.registerClient(token);
} catch (RemoteException e) {
Log.e(TAG, "Failed to initialize extension! Extension service does "
+ " not respond!");
}
+ if (!ret) {
+ mConnectionCount--;
+ }
- return false;
+ if (mConnectionCount <= 0) {
+ releaseProxyConnectionLocked(ctx);
+ }
+
+ return ret;
}
}
- public void unregisterClient(IBinder token) {
+ public void unregisterClient(Context ctx, IBinder token) {
synchronized (mLock) {
if (mProxy != null) {
try {
@@ -372,6 +390,11 @@ public final class CameraExtensionCharacteristics {
} catch (RemoteException e) {
Log.e(TAG, "Failed to de-initialize extension! Extension service does"
+ " not respond!");
+ } finally {
+ mConnectionCount--;
+ if (mConnectionCount <= 0) {
+ releaseProxyConnectionLocked(ctx);
+ }
}
}
}
@@ -446,8 +469,8 @@ public final class CameraExtensionCharacteristics {
/**
* @hide
*/
- public static void unregisterClient(IBinder token) {
- CameraExtensionManagerGlobal.get().unregisterClient(token);
+ public static void unregisterClient(Context ctx, IBinder token) {
+ CameraExtensionManagerGlobal.get().unregisterClient(ctx, token);
}
/**
@@ -578,7 +601,7 @@ public final class CameraExtensionCharacteristics {
}
}
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return Collections.unmodifiableList(ret);
@@ -626,7 +649,7 @@ public final class CameraExtensionCharacteristics {
Log.e(TAG, "Failed to query the extension for postview availability! Extension "
+ "service does not respond!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return false;
@@ -722,7 +745,7 @@ public final class CameraExtensionCharacteristics {
+ "service does not respond!");
return Collections.emptyList();
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
}
@@ -791,7 +814,7 @@ public final class CameraExtensionCharacteristics {
+ " not respond!");
return new ArrayList<>();
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
}
@@ -872,7 +895,7 @@ public final class CameraExtensionCharacteristics {
}
}
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
@@ -957,7 +980,7 @@ public final class CameraExtensionCharacteristics {
Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
+ " not respond!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return null;
@@ -998,7 +1021,7 @@ public final class CameraExtensionCharacteristics {
Log.e(TAG, "Failed to query the extension progress callbacks! Extension service does"
+ " not respond!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return false;
@@ -1075,7 +1098,7 @@ public final class CameraExtensionCharacteristics {
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture request keys!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return Collections.unmodifiableSet(ret);
@@ -1155,7 +1178,7 @@ public final class CameraExtensionCharacteristics {
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture result keys!");
} finally {
- unregisterClient(token);
+ unregisterClient(mContext, token);
}
return Collections.unmodifiableSet(ret);
diff --git a/core/java/android/hardware/camera2/camera_platform.aconfig b/core/java/android/hardware/camera2/camera_platform.aconfig
new file mode 100644
index 000000000000..67f63001ab58
--- /dev/null
+++ b/core/java/android/hardware/camera2/camera_platform.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.hardware.camera2"
+
+flag {
+ namespace: "camera_platform"
+ name: "initial_test_flag"
+ description: "Flag infrastructure test flag"
+ bug: "292631208"
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index e06699bbbd86..c7e74c077f0d 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -90,7 +90,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
private RequestProcessor mRequestProcessor = new RequestProcessor();
private final int mSessionId;
- private final IBinder mToken;
+ private IBinder mToken = null;
private Surface mClientRepeatingRequestSurface;
private Surface mClientCaptureSurface;
@@ -103,6 +103,8 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
private boolean mInitialized;
private boolean mSessionClosed;
+ private final Context mContext;
+
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock;
@@ -113,14 +115,9 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession(
@NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
@NonNull Map<String, CameraCharacteristics> characteristicsMap,
- @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId)
+ @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId,
+ @NonNull IBinder token)
throws CameraAccessException, RemoteException {
- final IBinder token = new Binder(TAG + " : " + sessionId);
- boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
- if (!success) {
- throw new UnsupportedOperationException("Unsupported extension!");
- }
-
String cameraId = cameraDevice.getId();
CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
cameraId, characteristicsMap);
@@ -204,8 +201,9 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
IAdvancedExtenderImpl extender = CameraExtensionCharacteristics.initializeAdvancedExtension(
config.getExtension());
extender.init(cameraId, characteristicsMapNative);
- CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(extender,
- cameraDevice, characteristicsMapNative, repeatingRequestSurface,
+
+ CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(ctx,
+ extender, cameraDevice, characteristicsMapNative, repeatingRequestSurface,
burstCaptureSurface, postviewSurface, config.getStateCallback(),
config.getExecutor(), sessionId, token);
@@ -217,13 +215,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
return ret;
}
- private CameraAdvancedExtensionSessionImpl(@NonNull IAdvancedExtenderImpl extender,
+ private CameraAdvancedExtensionSessionImpl(Context ctx,
+ @NonNull IAdvancedExtenderImpl extender,
@NonNull CameraDeviceImpl cameraDevice,
Map<String, CameraMetadataNative> characteristicsMap,
@Nullable Surface repeatingRequestSurface, @Nullable Surface burstCaptureSurface,
@Nullable Surface postviewSurface,
@NonNull StateCallback callback, @NonNull Executor executor,
- int sessionId, @NonNull IBinder token) {
+ int sessionId,
+ @NonNull IBinder token) {
+ mContext = ctx;
mAdvancedExtender = extender;
mCameraDevice = cameraDevice;
mCharacteristicsMap = characteristicsMap;
@@ -578,12 +579,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
mSessionProcessor = null;
}
- CameraExtensionCharacteristics.unregisterClient(mToken);
- if (mInitialized || (mCaptureSession != null)) {
- notifyClose = true;
- CameraExtensionCharacteristics.releaseSession();
+
+ if (mToken != null) {
+ if (mInitialized || (mCaptureSession != null)) {
+ notifyClose = true;
+ CameraExtensionCharacteristics.releaseSession();
+ }
+ CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
}
mInitialized = false;
+ mToken = null;
for (ImageReader reader : mReaderMap.values()) {
reader.close();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d3bde4b4b8a8..181ab2cf3421 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2550,19 +2550,32 @@ public class CameraDeviceImpl extends CameraDevice
HashMap<String, CameraCharacteristics> characteristicsMap = new HashMap<>(
mPhysicalIdsToChars);
characteristicsMap.put(mCameraId, mCharacteristics);
+ boolean initializationFailed = true;
+ IBinder token = new Binder(TAG + " : " + mNextSessionId++);
try {
+ boolean ret = CameraExtensionCharacteristics.registerClient(mContext, token);
+ if (!ret) {
+ token = null;
+ throw new UnsupportedOperationException("Unsupported extension!");
+ }
+
if (CameraExtensionCharacteristics.areAdvancedExtensionsSupported()) {
mCurrentAdvancedExtensionSession =
CameraAdvancedExtensionSessionImpl.createCameraAdvancedExtensionSession(
this, characteristicsMap, mContext, extensionConfiguration,
- mNextSessionId++);
+ mNextSessionId, token);
} else {
mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession(
this, characteristicsMap, mContext, extensionConfiguration,
- mNextSessionId++);
+ mNextSessionId, token);
}
+ initializationFailed = false;
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
+ } finally {
+ if (initializationFailed && (token != null)) {
+ CameraExtensionCharacteristics.unregisterClient(mContext, token);
+ }
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 5d256813ffb6..bf77681bbbbd 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -91,7 +91,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
private final Set<CaptureRequest.Key> mSupportedRequestKeys;
private final Set<CaptureResult.Key> mSupportedResultKeys;
private final ExtensionSessionStatsAggregator mStatsAggregator;
- private final IBinder mToken;
+ private IBinder mToken = null;
private boolean mCaptureResultsSupported;
private CameraCaptureSession mCaptureSession = null;
@@ -119,6 +119,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
// will do so internally.
private boolean mInternalRepeatingRequestEnabled = true;
+ private final Context mContext;
+
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock;
@@ -135,14 +137,9 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
@NonNull Map<String, CameraCharacteristics> characteristicsMap,
@NonNull Context ctx,
@NonNull ExtensionSessionConfiguration config,
- int sessionId)
+ int sessionId,
+ @NonNull IBinder token)
throws CameraAccessException, RemoteException {
- final IBinder token = new Binder(TAG + " : " + sessionId);
- boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
- if (!success) {
- throw new UnsupportedOperationException("Unsupported extension!");
- }
-
String cameraId = cameraDevice.getId();
CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
cameraId, characteristicsMap);
@@ -234,6 +231,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
characteristicsMap.get(cameraId).getNativeMetadata());
CameraExtensionSessionImpl session = new CameraExtensionSessionImpl(
+ ctx,
extenders.second,
extenders.first,
supportedPreviewSizes,
@@ -256,7 +254,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
return session;
}
- public CameraExtensionSessionImpl(@NonNull IImageCaptureExtenderImpl imageExtender,
+ public CameraExtensionSessionImpl(Context ctx, @NonNull IImageCaptureExtenderImpl imageExtender,
@NonNull IPreviewExtenderImpl previewExtender,
@NonNull List<Size> previewSizes,
@NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
@@ -269,6 +267,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
@NonNull IBinder token,
@NonNull Set<CaptureRequest.Key> requestKeys,
@Nullable Set<CaptureResult.Key> resultKeys) {
+ mContext = ctx;
mImageExtender = imageExtender;
mPreviewExtender = previewExtender;
mCameraDevice = cameraDevice;
@@ -878,12 +877,15 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
+ " respond!");
}
- CameraExtensionCharacteristics.unregisterClient(mToken);
- if (mInitialized || (mCaptureSession != null)) {
- notifyClose = true;
- CameraExtensionCharacteristics.releaseSession();
+ if (mToken != null) {
+ if (mInitialized || (mCaptureSession != null)) {
+ notifyClose = true;
+ CameraExtensionCharacteristics.releaseSession();
+ }
+ CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
}
mInitialized = false;
+ mToken = null;
if (mRepeatingRequestImageCallback != null) {
mRepeatingRequestImageCallback.close();
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index ef0db7f8a41c..b85d6869a1ff 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -509,8 +509,6 @@ public final class StreamConfigurationMap {
* Recommended for recording video (simple to use)
* <li>{@link android.media.MediaCodec} -
* Recommended for recording video (more complicated to use, with more flexibility)
- * <li>{@link android.renderscript.Allocation} -
- * Recommended for image processing with {@link android.renderscript RenderScript}
* <li>{@link android.view.SurfaceHolder} -
* Recommended for low-power camera preview with {@link android.view.SurfaceView}
* <li>{@link android.graphics.SurfaceTexture} -
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 42c56265bb4a..8482945dc1f0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -19,6 +19,7 @@ package android.os;
import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -55,6 +56,7 @@ import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.internal.os.CpuScalingPolicies;
+import com.android.internal.os.PowerStats;
import com.google.android.collect.Lists;
@@ -1793,75 +1795,55 @@ public abstract class BatteryStats {
}
/**
- * Measured energy delta from the previous reading.
+ * An extension to the history item describing a proc state change for a UID.
*/
- public static final class EnergyConsumerDetails {
+ public static final class ProcessStateChange {
+ public int uid;
+ public @BatteryConsumer.ProcessState int processState;
+
+ private static final int LARGE_UID_FLAG = 0x80000000;
+ private static final int SMALL_UID_MASK = 0x00FFFFFF;
+ private static final int PROC_STATE_MASK = 0x7F000000;
+ private static final int PROC_STATE_SHIFT = Integer.numberOfTrailingZeros(PROC_STATE_MASK);
+
/**
- * Description of the energy consumer, such as CPU, DISPLAY etc
+ * Writes this object to the supplied parcel.
*/
- public static final class EnergyConsumer {
- /**
- * See android.hardware.power.stats.EnergyConsumerType
- */
- public int type;
- /**
- * Used when there are multipe energy consumers of the same type, such
- * as CPU clusters, multiple displays on foldable devices etc.
- */
- public int ordinal;
- /**
- * Human-readable name of the energy consumer, e.g. "CPU"
- */
- public String name;
- }
- public EnergyConsumer[] consumers;
- public long[] chargeUC;
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- for (int i = 0; i < consumers.length; i++) {
- if (chargeUC[i] == POWER_DATA_UNAVAILABLE) {
- continue;
- }
- if (sb.length() != 0) {
- sb.append(' ');
- }
- sb.append(consumers[i].name);
- sb.append('=');
- sb.append(chargeUC[i]);
+ public void writeToParcel(Parcel out) {
+ int bits = processState << PROC_STATE_SHIFT;
+ if ((uid & ~SMALL_UID_MASK) == 0) {
+ bits |= uid;
+ out.writeInt(bits);
+ } else {
+ bits |= LARGE_UID_FLAG;
+ out.writeInt(bits);
+ out.writeInt(uid);
}
- return sb.toString();
}
- }
- /**
- * CPU usage for a given UID.
- */
- public static final class CpuUsageDetails {
/**
- * Descriptions of CPU power brackets, see PowerProfile.getCpuPowerBracketDescription
+ * Reads this object from the supplied parcel.
*/
- public String[] cpuBracketDescriptions;
- public int uid;
+ public void readFromParcel(Parcel in) {
+ int bits = in.readInt();
+ processState = (bits & PROC_STATE_MASK) >>> PROC_STATE_SHIFT;
+ if (processState >= BatteryConsumer.PROCESS_STATE_COUNT) {
+ Slog.e(TAG, "Unrecognized proc state in battery history: " + processState);
+ processState = BatteryConsumer.PROCESS_STATE_UNSPECIFIED;
+ }
+ if ((bits & LARGE_UID_FLAG) == 0) {
+ uid = bits & ~PROC_STATE_MASK;
+ } else {
+ uid = in.readInt();
+ }
+ }
+
/**
- * The delta, in milliseconds, per CPU power bracket, from the previous record for the
- * same UID.
+ * String representation for inclusion in the battery history dump.
*/
- public long[] cpuUsageMs;
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- UserHandle.formatUid(sb, uid);
- sb.append(": ");
- for (int bracket = 0; bracket < cpuUsageMs.length; bracket++) {
- if (bracket != 0) {
- sb.append(", ");
- }
- sb.append(cpuUsageMs[bracket]);
- }
- return sb.toString();
+ public String formatForBatteryHistory() {
+ return UserHandle.formatUid(uid) + ": "
+ + BatteryConsumer.processStateToString(processState);
}
}
@@ -2008,11 +1990,11 @@ public abstract class BatteryStats {
// Non-null when there is more detailed information at this step.
public HistoryStepDetails stepDetails;
- // Non-null when there is energy consumer information
- public EnergyConsumerDetails energyConsumerDetails;
+ // Non-null when there are power stats to be written to history
+ public PowerStats powerStats;
- // Non-null when there is CPU usage information
- public CpuUsageDetails cpuUsageDetails;
+ // Non-null when there is procstate change to be written to history
+ public ProcessStateChange processStateChange;
public static final int EVENT_FLAG_START = 0x8000;
public static final int EVENT_FLAG_FINISH = 0x4000;
@@ -2110,6 +2092,7 @@ public abstract class BatteryStats {
public final HistoryTag localWakelockTag = new HistoryTag();
public final HistoryTag localWakeReasonTag = new HistoryTag();
public final HistoryTag localEventTag = new HistoryTag();
+ public final ProcessStateChange localProcessStateChange = new ProcessStateChange();
// Includes a tag's first occurrence in the parcel, so the value of the tag is written
// rather than just its index in the history tag pool.
@@ -2222,8 +2205,8 @@ public abstract class BatteryStats {
eventCode = EVENT_NONE;
eventTag = null;
tagsFirstOccurrence = false;
- energyConsumerDetails = null;
- cpuUsageDetails = null;
+ powerStats = null;
+ processStateChange = null;
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -2273,8 +2256,8 @@ public abstract class BatteryStats {
}
tagsFirstOccurrence = o.tagsFirstOccurrence;
currentTime = o.currentTime;
- energyConsumerDetails = o.energyConsumerDetails;
- cpuUsageDetails = o.cpuUsageDetails;
+ powerStats = o.powerStats;
+ processStateChange = o.processStateChange;
}
public boolean sameNonEvent(HistoryItem o) {
@@ -2434,8 +2417,14 @@ public abstract class BatteryStats {
* Returns a BatteryStatsHistoryIterator. Battery history will continue being writable,
* but the iterator will continue iterating over the snapshot taken at the time this method
* is called.
+ *
+ * @param startTimeMs wall-clock time to start iterating from, inclusive
+ * @param endTimeMs wall-clock time to stop iterating, exclusive.
+ * Pass 0 to indicate current time.
*/
- public abstract BatteryStatsHistoryIterator iterateBatteryStatsHistory();
+ public abstract BatteryStatsHistoryIterator iterateBatteryStatsHistory(
+ @CurrentTimeMillisLong long startTimeMs,
+ @CurrentTimeMillisLong long endTimeMs);
/**
* Returns the number of times the device has been started.
@@ -6911,25 +6900,6 @@ public abstract class BatteryStats {
private String printNextItem(HistoryItem rec, long baseTime, boolean checkin,
boolean verbose) {
StringBuilder item = new StringBuilder();
-
- if (rec.cpuUsageDetails != null
- && rec.cpuUsageDetails.cpuBracketDescriptions != null
- && checkin) {
- String[] descriptions = rec.cpuUsageDetails.cpuBracketDescriptions;
- for (int bracket = 0; bracket < descriptions.length; bracket++) {
- item.append(BATTERY_STATS_CHECKIN_VERSION);
- item.append(',');
- item.append(HISTORY_DATA);
- item.append(",0,XB,");
- item.append(descriptions.length);
- item.append(',');
- item.append(bracket);
- item.append(',');
- item.append(descriptions[bracket]);
- item.append("\n");
- }
- }
-
if (!checkin) {
item.append(" ");
TimeUtils.formatDuration(
@@ -7165,57 +7135,19 @@ public abstract class BatteryStats {
item.append("\"");
}
}
- boolean firstExtension = true;
- if (rec.energyConsumerDetails != null) {
- firstExtension = false;
+ if (rec.powerStats != null && verbose) {
if (!checkin) {
- item.append(" ext=energy:");
- item.append(rec.energyConsumerDetails);
- } else {
- item.append(",XE");
- for (int i = 0; i < rec.energyConsumerDetails.consumers.length; i++) {
- if (rec.energyConsumerDetails.chargeUC[i] != POWER_DATA_UNAVAILABLE) {
- item.append(',');
- item.append(rec.energyConsumerDetails.consumers[i].name);
- item.append('=');
- item.append(rec.energyConsumerDetails.chargeUC[i]);
- }
- }
+ item.append(
+ "\n Stats: ");
+ item.append(rec.powerStats.formatForBatteryHistory(
+ "\n "));
}
}
- if (rec.cpuUsageDetails != null) {
+ if (rec.processStateChange != null && verbose) {
if (!checkin) {
- if (!firstExtension) {
- item.append("\n ");
- }
- String[] descriptions = rec.cpuUsageDetails.cpuBracketDescriptions;
- if (descriptions != null) {
- for (int bracket = 0; bracket < descriptions.length; bracket++) {
- item.append(" ext=cpu-bracket:");
- item.append(bracket);
- item.append(":");
- item.append(descriptions[bracket]);
- item.append("\n ");
- }
- }
- item.append(" ext=cpu:");
- item.append(rec.cpuUsageDetails);
- } else {
- if (!firstExtension) {
- item.append('\n');
- item.append(BATTERY_STATS_CHECKIN_VERSION);
- item.append(',');
- item.append(HISTORY_DATA);
- item.append(",0");
- }
- item.append(",XC,");
- item.append(rec.cpuUsageDetails.uid);
- for (int i = 0; i < rec.cpuUsageDetails.cpuUsageMs.length; i++) {
- item.append(',');
- item.append(rec.cpuUsageDetails.cpuUsageMs[i]);
- }
+ item.append(" procstate: ");
+ item.append(rec.processStateChange.formatForBatteryHistory());
}
- firstExtension = false;
}
item.append("\n");
if (rec.stepDetails != null) {
@@ -7537,7 +7469,7 @@ public abstract class BatteryStats {
long baseTime = -1;
boolean printed = false;
HistoryEventTracker tracker = null;
- try (BatteryStatsHistoryIterator iterator = iterateBatteryStatsHistory()) {
+ try (BatteryStatsHistoryIterator iterator = iterateBatteryStatsHistory(0, 0)) {
HistoryItem rec;
while ((rec = iterator.next()) != null) {
try {
@@ -8460,7 +8392,7 @@ public abstract class BatteryStats {
long baseTime = -1;
boolean printed = false;
HistoryEventTracker tracker = null;
- try (BatteryStatsHistoryIterator iterator = iterateBatteryStatsHistory()) {
+ try (BatteryStatsHistoryIterator iterator = iterateBatteryStatsHistory(0, 0)) {
HistoryItem rec;
while ((rec = iterator.next()) != null) {
lastTime = rec.time;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index e2c52cecc2b1..7586bf7700d9 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -315,7 +315,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
throw new IllegalStateException(
"Battery history was not requested in the BatteryUsageStatsQuery");
}
- return new BatteryStatsHistoryIterator(mBatteryStatsHistory);
+ return new BatteryStatsHistoryIterator(mBatteryStatsHistory, 0, 0);
}
@Override
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index eb4717057145..509c3b88441e 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1560,7 +1560,7 @@ public class Build {
String attestProp = getString(
TextUtils.formatSimple("ro.product.%s_for_attestation", property));
return attestProp.equals(UNKNOWN)
- ? getString(TextUtils.formatSimple("ro.product.vendor.%s", property)) : UNKNOWN;
+ ? getString(TextUtils.formatSimple("ro.product.vendor.%s", property)) : attestProp;
}
private static String[] getStringList(String property, String separator) {
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 403f55ceb94a..cf3546057549 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -364,7 +364,7 @@ public class DropBoxManager {
}
/**
- * Checks any blacklists (set in system settings) to see whether a certain
+ * Checks any denylists (set in system settings) to see whether a certain
* tag is allowed. Entries with disabled tags will be dropped immediately,
* so you can save the work of actually constructing and sending the data.
*
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index bf72b1d7a035..2cda787082c7 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -18,26 +18,19 @@ package android.os;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.hardware.vibrator.IVibrator;
+import android.os.vibrator.VibratorInfoFactory;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Range;
-import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.function.Function;
/**
* Vibrator implementation that controls the main system vibrator.
@@ -82,7 +75,7 @@ public class SystemVibrator extends Vibrator {
if (vibratorIds.length == 0) {
// It is known that the device has no vibrator, so cache and return info that
// reflects the lack of support for effects/primitives.
- return mVibratorInfo = new NoVibratorInfo();
+ return mVibratorInfo = VibratorInfo.EMPTY_VIBRATOR_INFO;
}
VibratorInfo[] vibratorInfos = new VibratorInfo[vibratorIds.length];
for (int i = 0; i < vibratorIds.length; i++) {
@@ -96,12 +89,7 @@ public class SystemVibrator extends Vibrator {
}
vibratorInfos[i] = vibrator.getInfo();
}
- if (vibratorInfos.length == 1) {
- // Device has a single vibrator info, cache and return successfully loaded info.
- return mVibratorInfo = new VibratorInfo(/* id= */ -1, vibratorInfos[0]);
- }
- // Device has multiple vibrators, generate a single info representing all of them.
- return mVibratorInfo = new MultiVibratorInfo(vibratorInfos);
+ return mVibratorInfo = VibratorInfoFactory.create(/* id= */ -1, vibratorInfos);
}
}
@@ -275,296 +263,6 @@ public class SystemVibrator extends Vibrator {
}
/**
- * Represents a device with no vibrator as a single {@link VibratorInfo}.
- *
- * @hide
- */
- @VisibleForTesting
- public static class NoVibratorInfo extends VibratorInfo {
- public NoVibratorInfo() {
- // Use empty arrays to indicate no support, while null would indicate support unknown.
- super(/* id= */ -1,
- /* capabilities= */ 0,
- /* supportedEffects= */ new SparseBooleanArray(),
- /* supportedBraking= */ new SparseBooleanArray(),
- /* supportedPrimitives= */ new SparseIntArray(),
- /* primitiveDelayMax= */ 0,
- /* compositionSizeMax= */ 0,
- /* pwlePrimitiveDurationMax= */ 0,
- /* pwleSizeMax= */ 0,
- /* qFactor= */ Float.NaN,
- new FrequencyProfile(/* resonantFrequencyHz= */ Float.NaN,
- /* minFrequencyHz= */ Float.NaN,
- /* frequencyResolutionHz= */ Float.NaN,
- /* maxAmplitudes= */ null));
- }
- }
-
- /**
- * Represents multiple vibrator information as a single {@link VibratorInfo}.
- *
- * <p>This uses an intersection of all vibrators to decide the capabilities and effect/primitive
- * support.
- *
- * @hide
- */
- @VisibleForTesting
- public static class MultiVibratorInfo extends VibratorInfo {
- // Epsilon used for float comparison applied in calculations for the merged info.
- private static final float EPSILON = 1e-5f;
-
- public MultiVibratorInfo(VibratorInfo[] vibrators) {
- // Need to use an extra constructor to share the computation in super initialization.
- this(vibrators, frequencyProfileIntersection(vibrators));
- }
-
- private MultiVibratorInfo(VibratorInfo[] vibrators,
- VibratorInfo.FrequencyProfile mergedProfile) {
- super(/* id= */ -1,
- capabilitiesIntersection(vibrators, mergedProfile.isEmpty()),
- supportedEffectsIntersection(vibrators),
- supportedBrakingIntersection(vibrators),
- supportedPrimitivesAndDurationsIntersection(vibrators),
- integerLimitIntersection(vibrators, VibratorInfo::getPrimitiveDelayMax),
- integerLimitIntersection(vibrators, VibratorInfo::getCompositionSizeMax),
- integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax),
- integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax),
- floatPropertyIntersection(vibrators, VibratorInfo::getQFactor),
- mergedProfile);
- }
-
- private static int capabilitiesIntersection(VibratorInfo[] infos,
- boolean frequencyProfileIsEmpty) {
- int intersection = ~0;
- for (VibratorInfo info : infos) {
- intersection &= info.getCapabilities();
- }
- if (frequencyProfileIsEmpty) {
- // Revoke frequency control if the merged frequency profile ended up empty.
- intersection &= ~IVibrator.CAP_FREQUENCY_CONTROL;
- }
- return intersection;
- }
-
- @Nullable
- private static SparseBooleanArray supportedBrakingIntersection(VibratorInfo[] infos) {
- for (VibratorInfo info : infos) {
- if (!info.isBrakingSupportKnown()) {
- // If one vibrator support is unknown, then the intersection is also unknown.
- return null;
- }
- }
-
- SparseBooleanArray intersection = new SparseBooleanArray();
- SparseBooleanArray firstVibratorBraking = infos[0].getSupportedBraking();
-
- brakingIdLoop:
- for (int i = 0; i < firstVibratorBraking.size(); i++) {
- int brakingId = firstVibratorBraking.keyAt(i);
- if (!firstVibratorBraking.valueAt(i)) {
- // The first vibrator already doesn't support this braking, so skip it.
- continue brakingIdLoop;
- }
-
- for (int j = 1; j < infos.length; j++) {
- if (!infos[j].hasBrakingSupport(brakingId)) {
- // One vibrator doesn't support this braking, so the intersection doesn't.
- continue brakingIdLoop;
- }
- }
-
- intersection.put(brakingId, true);
- }
-
- return intersection;
- }
-
- @Nullable
- private static SparseBooleanArray supportedEffectsIntersection(VibratorInfo[] infos) {
- for (VibratorInfo info : infos) {
- if (!info.isEffectSupportKnown()) {
- // If one vibrator support is unknown, then the intersection is also unknown.
- return null;
- }
- }
-
- SparseBooleanArray intersection = new SparseBooleanArray();
- SparseBooleanArray firstVibratorEffects = infos[0].getSupportedEffects();
-
- effectIdLoop:
- for (int i = 0; i < firstVibratorEffects.size(); i++) {
- int effectId = firstVibratorEffects.keyAt(i);
- if (!firstVibratorEffects.valueAt(i)) {
- // The first vibrator already doesn't support this effect, so skip it.
- continue effectIdLoop;
- }
-
- for (int j = 1; j < infos.length; j++) {
- if (infos[j].isEffectSupported(effectId) != VIBRATION_EFFECT_SUPPORT_YES) {
- // One vibrator doesn't support this effect, so the intersection doesn't.
- continue effectIdLoop;
- }
- }
-
- intersection.put(effectId, true);
- }
-
- return intersection;
- }
-
- @NonNull
- private static SparseIntArray supportedPrimitivesAndDurationsIntersection(
- VibratorInfo[] infos) {
- SparseIntArray intersection = new SparseIntArray();
- SparseIntArray firstVibratorPrimitives = infos[0].getSupportedPrimitives();
-
- primitiveIdLoop:
- for (int i = 0; i < firstVibratorPrimitives.size(); i++) {
- int primitiveId = firstVibratorPrimitives.keyAt(i);
- int primitiveDuration = firstVibratorPrimitives.valueAt(i);
- if (primitiveDuration == 0) {
- // The first vibrator already doesn't support this primitive, so skip it.
- continue primitiveIdLoop;
- }
-
- for (int j = 1; j < infos.length; j++) {
- int vibratorPrimitiveDuration = infos[j].getPrimitiveDuration(primitiveId);
- if (vibratorPrimitiveDuration == 0) {
- // One vibrator doesn't support this primitive, so the intersection doesn't.
- continue primitiveIdLoop;
- } else {
- // The primitive vibration duration is the maximum among all vibrators.
- primitiveDuration = Math.max(primitiveDuration, vibratorPrimitiveDuration);
- }
- }
-
- intersection.put(primitiveId, primitiveDuration);
- }
- return intersection;
- }
-
- private static int integerLimitIntersection(VibratorInfo[] infos,
- Function<VibratorInfo, Integer> propertyGetter) {
- int limit = 0; // Limit 0 means unlimited
- for (VibratorInfo info : infos) {
- int vibratorLimit = propertyGetter.apply(info);
- if ((limit == 0) || (vibratorLimit > 0 && vibratorLimit < limit)) {
- // This vibrator is limited and intersection is unlimited or has a larger limit:
- // use smaller limit here for the intersection.
- limit = vibratorLimit;
- }
- }
- return limit;
- }
-
- private static float floatPropertyIntersection(VibratorInfo[] infos,
- Function<VibratorInfo, Float> propertyGetter) {
- float property = propertyGetter.apply(infos[0]);
- if (Float.isNaN(property)) {
- // If one vibrator is undefined then the intersection is undefined.
- return Float.NaN;
- }
- for (int i = 1; i < infos.length; i++) {
- if (Float.compare(property, propertyGetter.apply(infos[i])) != 0) {
- // If one vibrator has a different value then the intersection is undefined.
- return Float.NaN;
- }
- }
- return property;
- }
-
- @NonNull
- private static FrequencyProfile frequencyProfileIntersection(VibratorInfo[] infos) {
- float freqResolution = floatPropertyIntersection(infos,
- info -> info.getFrequencyProfile().getFrequencyResolutionHz());
- float resonantFreq = floatPropertyIntersection(infos,
- VibratorInfo::getResonantFrequencyHz);
- Range<Float> freqRange = frequencyRangeIntersection(infos, freqResolution);
-
- if ((freqRange == null) || Float.isNaN(freqResolution)) {
- return new FrequencyProfile(resonantFreq, Float.NaN, freqResolution, null);
- }
-
- int amplitudeCount =
- Math.round(1 + (freqRange.getUpper() - freqRange.getLower()) / freqResolution);
- float[] maxAmplitudes = new float[amplitudeCount];
-
- // Use MAX_VALUE here to ensure that the FrequencyProfile constructor called with this
- // will fail if the loop below is broken and do not replace filled values with actual
- // vibrator measurements.
- Arrays.fill(maxAmplitudes, Float.MAX_VALUE);
-
- for (VibratorInfo info : infos) {
- Range<Float> vibratorFreqRange = info.getFrequencyProfile().getFrequencyRangeHz();
- float[] vibratorMaxAmplitudes = info.getFrequencyProfile().getMaxAmplitudes();
- int vibratorStartIdx = Math.round(
- (freqRange.getLower() - vibratorFreqRange.getLower()) / freqResolution);
- int vibratorEndIdx = vibratorStartIdx + maxAmplitudes.length - 1;
-
- if ((vibratorStartIdx < 0) || (vibratorEndIdx >= vibratorMaxAmplitudes.length)) {
- Slog.w(TAG, "Error calculating the intersection of vibrator frequency"
- + " profiles: attempted to fetch from vibrator "
- + info.getId() + " max amplitude with bad index " + vibratorStartIdx);
- return new FrequencyProfile(resonantFreq, Float.NaN, Float.NaN, null);
- }
-
- for (int i = 0; i < maxAmplitudes.length; i++) {
- maxAmplitudes[i] = Math.min(maxAmplitudes[i],
- vibratorMaxAmplitudes[vibratorStartIdx + i]);
- }
- }
-
- return new FrequencyProfile(resonantFreq, freqRange.getLower(),
- freqResolution, maxAmplitudes);
- }
-
- @Nullable
- private static Range<Float> frequencyRangeIntersection(VibratorInfo[] infos,
- float frequencyResolution) {
- Range<Float> firstRange = infos[0].getFrequencyProfile().getFrequencyRangeHz();
- if (firstRange == null) {
- // If one vibrator is undefined then the intersection is undefined.
- return null;
- }
- float intersectionLower = firstRange.getLower();
- float intersectionUpper = firstRange.getUpper();
-
- // Generate the intersection of all vibrator supported ranges, making sure that both
- // min supported frequencies are aligned w.r.t. the frequency resolution.
-
- for (int i = 1; i < infos.length; i++) {
- Range<Float> vibratorRange = infos[i].getFrequencyProfile().getFrequencyRangeHz();
- if (vibratorRange == null) {
- // If one vibrator is undefined then the intersection is undefined.
- return null;
- }
-
- if ((vibratorRange.getLower() >= intersectionUpper)
- || (vibratorRange.getUpper() <= intersectionLower)) {
- // If the range and intersection are disjoint then the intersection is undefined
- return null;
- }
-
- float frequencyDelta = Math.abs(intersectionLower - vibratorRange.getLower());
- if ((frequencyDelta % frequencyResolution) > EPSILON) {
- // If the intersection is not aligned with one vibrator then it's undefined
- return null;
- }
-
- intersectionLower = Math.max(intersectionLower, vibratorRange.getLower());
- intersectionUpper = Math.min(intersectionUpper, vibratorRange.getUpper());
- }
-
- if ((intersectionUpper - intersectionLower) < frequencyResolution) {
- // If the intersection is empty then it's undefined.
- return null;
- }
-
- return Range.create(intersectionLower, intersectionUpper);
- }
- }
-
- /**
* Listener for all vibrators state change.
*
* <p>This registers a listener to all vibrators to merge the callbacks into a single state
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 0b7d7c3cb877..4f8c24d1f905 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -156,6 +156,16 @@ public class VibratorInfo implements Parcelable {
return false;
}
VibratorInfo that = (VibratorInfo) o;
+ return mId == that.mId && equalContent(that);
+ }
+
+ /**
+ * Returns {@code true} only if the properties and capabilities of the provided info, except for
+ * the ID, equals to this info. Returns {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean equalContent(VibratorInfo that) {
int supportedPrimitivesCount = mSupportedPrimitives.size();
if (supportedPrimitivesCount != that.mSupportedPrimitives.size()) {
return false;
@@ -168,7 +178,7 @@ public class VibratorInfo implements Parcelable {
return false;
}
}
- return mId == that.mId && mCapabilities == that.mCapabilities
+ return mCapabilities == that.mCapabilities
&& mPrimitiveDelayMax == that.mPrimitiveDelayMax
&& mCompositionSizeMax == that.mCompositionSizeMax
&& mPwlePrimitiveDurationMax == that.mPwlePrimitiveDurationMax
@@ -445,7 +455,8 @@ public class VibratorInfo implements Parcelable {
return mFrequencyProfile;
}
- protected long getCapabilities() {
+ /** Returns a single int representing all the capabilities of the vibrator. */
+ public long getCapabilities() {
return mCapabilities;
}
diff --git a/core/java/android/os/vibrator/MultiVibratorInfo.java b/core/java/android/os/vibrator/MultiVibratorInfo.java
new file mode 100644
index 000000000000..5f3273129213
--- /dev/null
+++ b/core/java/android/os/vibrator/MultiVibratorInfo.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.vibrator;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.vibrator.IVibrator;
+import android.os.Vibrator;
+import android.os.VibratorInfo;
+import android.util.Range;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import java.util.Arrays;
+import java.util.function.Function;
+
+/**
+ * Represents multiple vibrator information as a single {@link VibratorInfo}.
+ *
+ * <p>This uses an intersection of all vibrators to decide the capabilities and effect/primitive
+ * support.
+ *
+ * @hide
+ */
+public final class MultiVibratorInfo extends VibratorInfo {
+ private static final String TAG = "MultiVibratorInfo";
+
+ // Epsilon used for float comparison applied in calculations for the merged info.
+ private static final float EPSILON = 1e-5f;
+
+ public MultiVibratorInfo(int id, VibratorInfo[] vibrators) {
+ this(id, vibrators, frequencyProfileIntersection(vibrators));
+ }
+
+ private MultiVibratorInfo(
+ int id, VibratorInfo[] vibrators, VibratorInfo.FrequencyProfile mergedProfile) {
+ super(id,
+ capabilitiesIntersection(vibrators, mergedProfile.isEmpty()),
+ supportedEffectsIntersection(vibrators),
+ supportedBrakingIntersection(vibrators),
+ supportedPrimitivesAndDurationsIntersection(vibrators),
+ integerLimitIntersection(vibrators, VibratorInfo::getPrimitiveDelayMax),
+ integerLimitIntersection(vibrators, VibratorInfo::getCompositionSizeMax),
+ integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax),
+ integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax),
+ floatPropertyIntersection(vibrators, VibratorInfo::getQFactor),
+ mergedProfile);
+ }
+
+ private static int capabilitiesIntersection(VibratorInfo[] infos,
+ boolean frequencyProfileIsEmpty) {
+ int intersection = ~0;
+ for (VibratorInfo info : infos) {
+ intersection &= info.getCapabilities();
+ }
+ if (frequencyProfileIsEmpty) {
+ // Revoke frequency control if the merged frequency profile ended up empty.
+ intersection &= ~IVibrator.CAP_FREQUENCY_CONTROL;
+ }
+ return intersection;
+ }
+
+ @Nullable
+ private static SparseBooleanArray supportedBrakingIntersection(VibratorInfo[] infos) {
+ for (VibratorInfo info : infos) {
+ if (!info.isBrakingSupportKnown()) {
+ // If one vibrator support is unknown, then the intersection is also unknown.
+ return null;
+ }
+ }
+
+ SparseBooleanArray intersection = new SparseBooleanArray();
+ SparseBooleanArray firstVibratorBraking = infos[0].getSupportedBraking();
+
+ brakingIdLoop:
+ for (int i = 0; i < firstVibratorBraking.size(); i++) {
+ int brakingId = firstVibratorBraking.keyAt(i);
+ if (!firstVibratorBraking.valueAt(i)) {
+ // The first vibrator already doesn't support this braking, so skip it.
+ continue brakingIdLoop;
+ }
+
+ for (int j = 1; j < infos.length; j++) {
+ if (!infos[j].hasBrakingSupport(brakingId)) {
+ // One vibrator doesn't support this braking, so the intersection doesn't.
+ continue brakingIdLoop;
+ }
+ }
+
+ intersection.put(brakingId, true);
+ }
+
+ return intersection;
+ }
+
+ @Nullable
+ private static SparseBooleanArray supportedEffectsIntersection(VibratorInfo[] infos) {
+ for (VibratorInfo info : infos) {
+ if (!info.isEffectSupportKnown()) {
+ // If one vibrator support is unknown, then the intersection is also unknown.
+ return null;
+ }
+ }
+
+ SparseBooleanArray intersection = new SparseBooleanArray();
+ SparseBooleanArray firstVibratorEffects = infos[0].getSupportedEffects();
+
+ effectIdLoop:
+ for (int i = 0; i < firstVibratorEffects.size(); i++) {
+ int effectId = firstVibratorEffects.keyAt(i);
+ if (!firstVibratorEffects.valueAt(i)) {
+ // The first vibrator already doesn't support this effect, so skip it.
+ continue effectIdLoop;
+ }
+
+ for (int j = 1; j < infos.length; j++) {
+ if (infos[j].isEffectSupported(effectId) != Vibrator.VIBRATION_EFFECT_SUPPORT_YES) {
+ // One vibrator doesn't support this effect, so the intersection doesn't.
+ continue effectIdLoop;
+ }
+ }
+
+ intersection.put(effectId, true);
+ }
+
+ return intersection;
+ }
+
+ @NonNull
+ private static SparseIntArray supportedPrimitivesAndDurationsIntersection(
+ VibratorInfo[] infos) {
+ SparseIntArray intersection = new SparseIntArray();
+ SparseIntArray firstVibratorPrimitives = infos[0].getSupportedPrimitives();
+
+ primitiveIdLoop:
+ for (int i = 0; i < firstVibratorPrimitives.size(); i++) {
+ int primitiveId = firstVibratorPrimitives.keyAt(i);
+ int primitiveDuration = firstVibratorPrimitives.valueAt(i);
+ if (primitiveDuration == 0) {
+ // The first vibrator already doesn't support this primitive, so skip it.
+ continue primitiveIdLoop;
+ }
+
+ for (int j = 1; j < infos.length; j++) {
+ int vibratorPrimitiveDuration = infos[j].getPrimitiveDuration(primitiveId);
+ if (vibratorPrimitiveDuration == 0) {
+ // One vibrator doesn't support this primitive, so the intersection doesn't.
+ continue primitiveIdLoop;
+ } else {
+ // The primitive vibration duration is the maximum among all vibrators.
+ primitiveDuration = Math.max(primitiveDuration, vibratorPrimitiveDuration);
+ }
+ }
+
+ intersection.put(primitiveId, primitiveDuration);
+ }
+ return intersection;
+ }
+
+ private static int integerLimitIntersection(VibratorInfo[] infos,
+ Function<VibratorInfo, Integer> propertyGetter) {
+ int limit = 0; // Limit 0 means unlimited
+ for (VibratorInfo info : infos) {
+ int vibratorLimit = propertyGetter.apply(info);
+ if ((limit == 0) || (vibratorLimit > 0 && vibratorLimit < limit)) {
+ // This vibrator is limited and intersection is unlimited or has a larger limit:
+ // use smaller limit here for the intersection.
+ limit = vibratorLimit;
+ }
+ }
+ return limit;
+ }
+
+ private static float floatPropertyIntersection(VibratorInfo[] infos,
+ Function<VibratorInfo, Float> propertyGetter) {
+ float property = propertyGetter.apply(infos[0]);
+ if (Float.isNaN(property)) {
+ // If one vibrator is undefined then the intersection is undefined.
+ return Float.NaN;
+ }
+ for (int i = 1; i < infos.length; i++) {
+ if (Float.compare(property, propertyGetter.apply(infos[i])) != 0) {
+ // If one vibrator has a different value then the intersection is undefined.
+ return Float.NaN;
+ }
+ }
+ return property;
+ }
+
+ @NonNull
+ private static FrequencyProfile frequencyProfileIntersection(VibratorInfo[] infos) {
+ float freqResolution = floatPropertyIntersection(infos,
+ info -> info.getFrequencyProfile().getFrequencyResolutionHz());
+ float resonantFreq = floatPropertyIntersection(infos,
+ VibratorInfo::getResonantFrequencyHz);
+ Range<Float> freqRange = frequencyRangeIntersection(infos, freqResolution);
+
+ if ((freqRange == null) || Float.isNaN(freqResolution)) {
+ return new FrequencyProfile(resonantFreq, Float.NaN, freqResolution, null);
+ }
+
+ int amplitudeCount =
+ Math.round(1 + (freqRange.getUpper() - freqRange.getLower()) / freqResolution);
+ float[] maxAmplitudes = new float[amplitudeCount];
+
+ // Use MAX_VALUE here to ensure that the FrequencyProfile constructor called with this
+ // will fail if the loop below is broken and do not replace filled values with actual
+ // vibrator measurements.
+ Arrays.fill(maxAmplitudes, Float.MAX_VALUE);
+
+ for (VibratorInfo info : infos) {
+ Range<Float> vibratorFreqRange = info.getFrequencyProfile().getFrequencyRangeHz();
+ float[] vibratorMaxAmplitudes = info.getFrequencyProfile().getMaxAmplitudes();
+ int vibratorStartIdx = Math.round(
+ (freqRange.getLower() - vibratorFreqRange.getLower()) / freqResolution);
+ int vibratorEndIdx = vibratorStartIdx + maxAmplitudes.length - 1;
+
+ if ((vibratorStartIdx < 0) || (vibratorEndIdx >= vibratorMaxAmplitudes.length)) {
+ Slog.w(TAG, "Error calculating the intersection of vibrator frequency"
+ + " profiles: attempted to fetch from vibrator "
+ + info.getId() + " max amplitude with bad index " + vibratorStartIdx);
+ return new FrequencyProfile(resonantFreq, Float.NaN, Float.NaN, null);
+ }
+
+ for (int i = 0; i < maxAmplitudes.length; i++) {
+ maxAmplitudes[i] = Math.min(maxAmplitudes[i],
+ vibratorMaxAmplitudes[vibratorStartIdx + i]);
+ }
+ }
+
+ return new FrequencyProfile(resonantFreq, freqRange.getLower(),
+ freqResolution, maxAmplitudes);
+ }
+
+ @Nullable
+ private static Range<Float> frequencyRangeIntersection(VibratorInfo[] infos,
+ float frequencyResolution) {
+ Range<Float> firstRange = infos[0].getFrequencyProfile().getFrequencyRangeHz();
+ if (firstRange == null) {
+ // If one vibrator is undefined then the intersection is undefined.
+ return null;
+ }
+ float intersectionLower = firstRange.getLower();
+ float intersectionUpper = firstRange.getUpper();
+
+ // Generate the intersection of all vibrator supported ranges, making sure that both
+ // min supported frequencies are aligned w.r.t. the frequency resolution.
+
+ for (int i = 1; i < infos.length; i++) {
+ Range<Float> vibratorRange = infos[i].getFrequencyProfile().getFrequencyRangeHz();
+ if (vibratorRange == null) {
+ // If one vibrator is undefined then the intersection is undefined.
+ return null;
+ }
+
+ if ((vibratorRange.getLower() >= intersectionUpper)
+ || (vibratorRange.getUpper() <= intersectionLower)) {
+ // If the range and intersection are disjoint then the intersection is undefined
+ return null;
+ }
+
+ float frequencyDelta = Math.abs(intersectionLower - vibratorRange.getLower());
+ if ((frequencyDelta % frequencyResolution) > EPSILON) {
+ // If the intersection is not aligned with one vibrator then it's undefined
+ return null;
+ }
+
+ intersectionLower = Math.max(intersectionLower, vibratorRange.getLower());
+ intersectionUpper = Math.min(intersectionUpper, vibratorRange.getUpper());
+ }
+
+ if ((intersectionUpper - intersectionLower) < frequencyResolution) {
+ // If the intersection is empty then it's undefined.
+ return null;
+ }
+
+ return Range.create(intersectionLower, intersectionUpper);
+ }
+}
diff --git a/core/java/android/os/vibrator/VibratorInfoFactory.java b/core/java/android/os/vibrator/VibratorInfoFactory.java
new file mode 100644
index 000000000000..d10d7ec222c3
--- /dev/null
+++ b/core/java/android/os/vibrator/VibratorInfoFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.vibrator;
+
+import android.annotation.NonNull;
+import android.os.VibratorInfo;
+
+/**
+ * Factory for creating {@link VibratorInfo}s.
+ *
+ * @hide
+ */
+public final class VibratorInfoFactory {
+ /**
+ * Creates a single {@link VibratorInfo} that is an intersection of a given collection of
+ * {@link VibratorInfo}s. That is, the capabilities of the returned info will be an
+ * intersection of that of the provided infos.
+ *
+ * @param id the ID for the new {@link VibratorInfo}.
+ * @param vibratorInfos the {@link VibratorInfo}s from which to create a single
+ * {@link VibratorInfo}.
+ * @return a {@link VibratorInfo} that represents the intersection of {@code vibratorInfos}.
+ */
+ @NonNull
+ public static VibratorInfo create(int id, @NonNull VibratorInfo[] vibratorInfos) {
+ if (vibratorInfos.length == 0) {
+ return new VibratorInfo.Builder(id).build();
+ }
+ if (vibratorInfos.length == 1) {
+ // Create an equivalent info with the requested ID.
+ return new VibratorInfo(id, vibratorInfos[0]);
+ }
+ // Create a MultiVibratorInfo that intersects all the given infos and has the requested ID.
+ return new MultiVibratorInfo(id, vibratorInfos);
+ }
+
+ private VibratorInfoFactory() {}
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index abc8bf51b67b..2791c412f5c7 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1450,7 +1450,7 @@ public final class Settings {
/**
* Activity Action: Ask the user to allow an app to ignore battery optimizations (that is,
- * put them on the whitelist of apps shown by
+ * put them on the allowlist of apps shown by
* {@link #ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}). For an app to use this, it also
* must hold the {@link android.Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}
* permission.
@@ -3524,7 +3524,6 @@ public final class Settings {
public ArrayMap<String, String> getStringsForPrefix(ContentResolver cr, String prefix,
List<String> names) {
String namespace = prefix.substring(0, prefix.length() - 1);
- Config.enforceReadPermission(namespace);
ArrayMap<String, String> keyValues = new ArrayMap<>();
int currentGeneration = -1;
boolean needsGenerationTracker = false;
@@ -12378,7 +12377,7 @@ public final class Settings {
public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
/**
- * The package name for the custom bugreport handler app. This app must be whitelisted.
+ * The package name for the custom bugreport handler app. This app must be allowlisted.
* This is currently used only by Power Menu short press.
* @deprecated Use {@link android.provider.Settings.Secure#CUSTOM_BUGREPORT_HANDLER_APP}
* instead
@@ -12794,7 +12793,7 @@ public final class Settings {
"location_background_throttle_proximity_alert_interval_ms";
/**
- * Packages that are whitelisted for background throttling (throttling will not be applied).
+ * Packages that are allowlisted for background throttling (throttling will not be applied).
* @hide
*/
@Readable
@@ -12802,7 +12801,7 @@ public final class Settings {
"location_background_throttle_package_whitelist";
/**
- * Packages that are whitelisted for ignoring location settings (may retrieve location even
+ * Packages that are allowlisted for ignoring location settings (may retrieve location even
* when user location settings are off), for emergency purposes.
* @deprecated No longer used from Android 12+
* @hide
@@ -13386,7 +13385,7 @@ public final class Settings {
/**
* List of certificate (hex string representation of the application's certificate - SHA-1
- * or SHA-256) and carrier app package pairs which are whitelisted to prompt the user for
+ * or SHA-256) and carrier app package pairs which are allowlisted to prompt the user for
* install when a sim card with matching UICC carrier privilege rules is inserted. The
* certificate is used as a key, so the certificate encoding here must be the same as the
* certificate encoding used on the SIM.
@@ -16787,7 +16786,7 @@ public final class Settings {
"enable_adb_incremental_install_default";
/**
- * The packages whitelisted to be run in autofill compatibility mode. The list
+ * The packages allowlisted to be run in autofill compatibility mode. The list
* of packages is {@code ":"} colon delimited, and each entry has the name of the
* package and an optional list of url bar resource ids (the list is delimited by
* brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
@@ -16847,7 +16846,7 @@ public final class Settings {
public static final String STYLUS_EVER_USED = "stylus_ever_used";
/**
- * Exemptions to the hidden API blacklist.
+ * Exemptions to the hidden API denylist.
*
* @hide
*/
@@ -19648,21 +19647,6 @@ public final class Settings {
.getApplicationContext().checkCallingOrSelfPermission(permission);
}
- /**
- * Enforces READ_DEVICE_CONFIG permission if namespace is not one of public namespaces.
- * @hide
- */
- public static void enforceReadPermission(String namespace) {
- if (ActivityThread.currentApplication().getApplicationContext()
- .checkCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG)
- != PackageManager.PERMISSION_GRANTED) {
- if (!DeviceConfig.getPublicNamespaces().contains(namespace)) {
- throw new SecurityException("Permission denial: reading from settings requires:"
- + Manifest.permission.READ_DEVICE_CONFIG);
- }
- }
- }
-
private static void setMonitorCallbackAsUser(
@NonNull @CallbackExecutor Executor executor,
@NonNull ContentResolver resolver, @UserIdInt int userHandle,
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index 910fc44988b2..c027981070f9 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -64,6 +64,7 @@ public final class Tile implements Parcelable {
private IBinder mToken;
private Icon mIcon;
private CharSequence mLabel;
+ private CharSequence mDefaultLabel;
private CharSequence mSubtitle;
private CharSequence mContentDescription;
private CharSequence mStateDescription;
@@ -142,10 +143,25 @@ public final class Tile implements Parcelable {
* Gets the current label for the tile.
*/
public CharSequence getLabel() {
+ return mLabel != null ? mLabel : mDefaultLabel;
+ }
+
+ /**
+ * @hide
+ * @return
+ */
+ public CharSequence getCustomLabel() {
return mLabel;
}
/**
+ * @hide
+ */
+ public void setDefaultLabel(CharSequence defaultLabel) {
+ mDefaultLabel = defaultLabel;
+ }
+
+ /**
* Sets the current label for the tile.
*
* Does not take effect until {@link #updateTile()} is called.
@@ -267,6 +283,7 @@ public final class Tile implements Parcelable {
}
dest.writeInt(mState);
TextUtils.writeToParcel(mLabel, dest, flags);
+ TextUtils.writeToParcel(mDefaultLabel, dest, flags);
TextUtils.writeToParcel(mSubtitle, dest, flags);
TextUtils.writeToParcel(mContentDescription, dest, flags);
TextUtils.writeToParcel(mStateDescription, dest, flags);
@@ -285,6 +302,7 @@ public final class Tile implements Parcelable {
}
mState = source.readInt();
mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ mDefaultLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
mStateDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index 511cb2df712d..ac76fc2eb469 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -212,6 +212,11 @@ public class IntArray implements Cloneable {
return -1;
}
+ /** Returns {@code true} if this array contains the specified value. */
+ public boolean contains(int value) {
+ return indexOf(value) != -1;
+ }
+
/**
* Removes the value at the specified index from this array.
*/
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index c7fd38092ec7..37663d59cafd 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -21,6 +21,7 @@ import android.graphics.Rect;
import android.view.RemoteAnimationTarget;
import android.view.IRecentsAnimationController;
import android.window.TaskSnapshot;
+import android.os.Bundle;
/**
* Interface that is used to callback from window manager to the process that runs a recents
@@ -57,7 +58,7 @@ oneway interface IRecentsAnimationRunner {
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
void onAnimationStart(in IRecentsAnimationController controller,
in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers,
- in Rect homeContentInsets, in Rect minimizedHomeBounds) = 2;
+ in Rect homeContentInsets, in Rect minimizedHomeBounds, in Bundle extras) = 2;
/**
* Called when the task of an activity that has been started while the recents animation
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 3812d37a5fed..2761aaeb4a7d 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -19,6 +19,7 @@ package android.view;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Matrix;
+import android.graphics.Rect;
import android.graphics.Region;
import android.gui.TouchOcclusionMode;
import android.os.IBinder;
@@ -103,10 +104,7 @@ public final class InputWindowHandle {
public long dispatchingTimeoutMillis;
// Window frame.
- public int frameLeft;
- public int frameTop;
- public int frameRight;
- public int frameBottom;
+ public final Rect frame = new Rect();
public int surfaceInset;
@@ -184,10 +182,7 @@ public final class InputWindowHandle {
layoutParamsFlags = other.layoutParamsFlags;
layoutParamsType = other.layoutParamsType;
dispatchingTimeoutMillis = other.dispatchingTimeoutMillis;
- frameLeft = other.frameLeft;
- frameTop = other.frameTop;
- frameRight = other.frameRight;
- frameBottom = other.frameBottom;
+ frame.set(other.frame);
surfaceInset = other.surfaceInset;
scaleFactor = other.scaleFactor;
touchableRegion.set(other.touchableRegion);
@@ -209,8 +204,7 @@ public final class InputWindowHandle {
@Override
public String toString() {
return new StringBuilder(name != null ? name : "")
- .append(", frame=[").append(frameLeft).append(",").append(frameTop).append(",")
- .append(frameRight).append(",").append(frameBottom).append("]")
+ .append(", frame=[").append(frame).append("]")
.append(", touchableRegion=").append(touchableRegion)
.append(", scaleFactor=").append(scaleFactor)
.append(", transform=").append(transform)
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 6c5f195ba2a0..fabfed39a913 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -28,7 +28,6 @@ import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION;
import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS;
import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH;
import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX;
-import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsController.DEBUG;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
@@ -285,15 +284,11 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
return false;
}
final Insets offset = Insets.subtract(mShownInsets, mPendingInsets);
- ArrayList<SurfaceParams> params = new ArrayList<>();
- updateLeashesForSide(ISIDE_LEFT, offset.left, mPendingInsets.left, params, outState,
- mPendingAlpha);
- updateLeashesForSide(ISIDE_TOP, offset.top, mPendingInsets.top, params, outState,
- mPendingAlpha);
- updateLeashesForSide(ISIDE_RIGHT, offset.right, mPendingInsets.right, params, outState,
- mPendingAlpha);
- updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mPendingInsets.bottom, params, outState,
- mPendingAlpha);
+ final ArrayList<SurfaceParams> params = new ArrayList<>();
+ updateLeashesForSide(ISIDE_LEFT, offset.left, params, outState, mPendingAlpha);
+ updateLeashesForSide(ISIDE_TOP, offset.top, params, outState, mPendingAlpha);
+ updateLeashesForSide(ISIDE_RIGHT, offset.right, params, outState, mPendingAlpha);
+ updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, params, outState, mPendingAlpha);
mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()]));
mCurrentInsets = mPendingInsets;
@@ -457,7 +452,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
return alpha >= 1 ? 1 : (alpha <= 0 ? 0 : alpha);
}
- private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int inset,
+ private void updateLeashesForSide(@InternalInsetsSide int side, int offset,
ArrayList<SurfaceParams> surfaceParams, @Nullable InsetsState outState, float alpha) {
final ArraySet<InsetsSourceControl> controls = mSideControlsMap.get(side);
if (controls == null) {
@@ -475,9 +470,9 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
}
addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);
- final boolean visible = mHasZeroInsetsIme && side == ISIDE_BOTTOM
- ? (mAnimationType == ANIMATION_TYPE_SHOW || !mFinished)
- : inset != 0;
+ final boolean visible = mPendingFraction == 0 && source != null
+ ? source.isVisible()
+ : !mFinished || mShownOnFinish;
if (outState != null && source != null) {
outState.addSource(new InsetsSource(source)
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c6d8bd18bc28..8ec7d6779392 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -666,9 +666,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
/** Set of inset types for which an animation was started since last resetting this field */
private @InsetsType int mLastStartedAnimTypes;
- /** Set of inset types which cannot be controlled by the user animation */
- private @InsetsType int mDisabledUserAnimationInsetsTypes;
-
/** Set of inset types which are existing */
private @InsetsType int mExistingTypes = 0;
@@ -887,21 +884,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
mState.set(newState, 0 /* types */);
@InsetsType int existingTypes = 0;
@InsetsType int visibleTypes = 0;
- @InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (int i = 0, size = newState.sourceSize(); i < size; i++) {
final InsetsSource source = newState.sourceAt(i);
@InsetsType int type = source.getType();
@AnimationType int animationType = getAnimationType(type);
- if (!source.isUserControllable()) {
- // The user animation is not allowed when visible frame is empty.
- disabledUserAnimationTypes |= type;
- if (animationType == ANIMATION_TYPE_USER) {
- // Existing user animation needs to be cancelled.
- animationType = ANIMATION_TYPE_NONE;
- cancelledUserAnimationTypes[0] |= type;
- }
- }
final InsetsSourceConsumer consumer = mSourceConsumers.get(source.getId());
if (consumer != null) {
consumer.updateSource(source, animationType);
@@ -931,28 +918,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
InsetsState.traverse(mState, newState, mRemoveGoneSources);
- updateDisabledUserAnimationTypes(disabledUserAnimationTypes);
-
if (cancelledUserAnimationTypes[0] != 0) {
mHandler.post(() -> show(cancelledUserAnimationTypes[0]));
}
}
- private void updateDisabledUserAnimationTypes(@InsetsType int disabledUserAnimationTypes) {
- @InsetsType int diff = mDisabledUserAnimationInsetsTypes ^ disabledUserAnimationTypes;
- if (diff != 0) {
- for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
- InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
- if (consumer.getControl() != null && (consumer.getType() & diff) != 0) {
- mHandler.removeCallbacks(mInvokeControllableInsetsChangedListeners);
- mHandler.post(mInvokeControllableInsetsChangedListeners);
- break;
- }
- }
- mDisabledUserAnimationInsetsTypes = disabledUserAnimationTypes;
- }
- }
-
private boolean captionInsetsUnchanged() {
if (CAPTION_ON_SHELL) {
return false;
@@ -1332,26 +1302,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
+ " while an existing " + Type.toString(mTypesBeingCancelled)
+ " is being cancelled.");
}
- if (animationType == ANIMATION_TYPE_USER) {
- final @InsetsType int disabledTypes = types & mDisabledUserAnimationInsetsTypes;
- if (DEBUG) Log.d(TAG, "user animation disabled types: " + disabledTypes);
- types &= ~mDisabledUserAnimationInsetsTypes;
-
- if ((disabledTypes & ime()) != 0) {
- ImeTracker.forLogging().onFailed(statsToken,
- ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
-
- if (fromIme
- && !mState.isSourceOrDefaultVisible(mImeSourceConsumer.getId(), ime())) {
- // We've requested IMM to show IME, but the IME is not controllable. We need to
- // cancel the request.
- setRequestedVisibleTypes(0 /* visibleTypes */, ime());
- if (mImeSourceConsumer.onAnimationStateChanged(false /* running */)) {
- notifyVisibilityChanged();
- }
- }
- }
- }
if (types == 0) {
// nothing to animate.
listener.onCancelled(null);
@@ -1954,7 +1904,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
InsetsSource source = mState.peekSource(consumer.getId());
- if (consumer.getControl() != null && source != null && source.isUserControllable()) {
+ if (consumer.getControl() != null && source != null) {
result |= consumer.getType();
}
}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index ff009ed09329..0d5704eed4b3 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -187,11 +187,6 @@ public class InsetsSource implements Parcelable {
return (mFlags & flags) == flags;
}
- boolean isUserControllable() {
- // If mVisibleFrame is null, it will be the same area as mFrame.
- return mVisibleFrame == null || !mVisibleFrame.isEmpty();
- }
-
/**
* Calculates the insets this source will cause to a client window.
*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 92509c969055..5e19c675bb88 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9279,8 +9279,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
while (parentGroup != null && !parentGroup.isImportantForAutofill()) {
- ignoredParentLeft += parentGroup.mLeft;
- ignoredParentTop += parentGroup.mTop;
+ ignoredParentLeft += parentGroup.mLeft - parentGroup.mScrollX;
+ ignoredParentTop += parentGroup.mTop - parentGroup.mScrollY;
viewParent = parentGroup.getParent();
if (viewParent instanceof View) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e6ecd6e503c1..ddd3269925a4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -322,13 +322,6 @@ public final class ViewRootImpl implements ViewParent,
SystemProperties.getBoolean("persist.wm.debug.client_immersive_confirmation", false);
/**
- * Whether the client should compute the window frame on its own.
- * @hide
- */
- public static final boolean LOCAL_LAYOUT =
- SystemProperties.getBoolean("persist.debug.local_layout", true);
-
- /**
* Set this system property to true to force the view hierarchy to render
* at 60 Hz. This can be used to measure the potential framerate.
*/
@@ -1912,8 +1905,8 @@ public final class ViewRootImpl implements ViewParent,
final float compatScale = frames.compatScale;
final boolean frameChanged = !mWinFrame.equals(frame);
final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration);
- final boolean attachedFrameChanged = LOCAL_LAYOUT
- && !Objects.equals(mTmpFrames.attachedFrame, attachedFrame);
+ final boolean attachedFrameChanged =
+ !Objects.equals(mTmpFrames.attachedFrame, attachedFrame);
final boolean displayChanged = mDisplay.getDisplayId() != displayId;
final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale;
final boolean dragResizingChanged = mPendingDragResizing != dragResizing;
@@ -8309,8 +8302,7 @@ public final class ViewRootImpl implements ViewParent,
final int measuredWidth = mMeasuredWidth;
final int measuredHeight = mMeasuredHeight;
final boolean relayoutAsync;
- if (LOCAL_LAYOUT
- && (mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
+ if ((mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
&& mWindowAttributes.type != TYPE_APPLICATION_STARTING
&& mSyncSeqId <= mLastSyncSeqId
&& winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index afe755924e08..8899f5cd91d4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12884,6 +12884,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * @return true if this TextView could be filled by an Autofill service. Note that disabled
+ * fields can still be filled.
+ */
+ @UnsupportedAppUsage
+ boolean isTextAutofillable() {
+ return mText instanceof Editable && onCheckIsTextEditor();
+ }
+
+ /**
* Returns true, only while processing a touch gesture, if the initial
* touch down event caused focus to move to the text view and as a result
* its selection changed. Only valid while processing the touch gesture
@@ -13605,7 +13614,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void autofill(AutofillValue value) {
- if (!isTextEditable()) {
+ if (!isTextAutofillable()) {
Log.w(LOG_TAG, "cannot autofill non-editable TextView: " + this);
return;
}
@@ -13621,7 +13630,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public @AutofillType int getAutofillType() {
- return isTextEditable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE;
+ return isTextAutofillable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE;
}
/**
@@ -13635,7 +13644,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
@Nullable
public AutofillValue getAutofillValue() {
- if (isTextEditable()) {
+ if (isTextAutofillable()) {
final CharSequence text = TextUtils.trimToParcelableSize(getText());
return AutofillValue.forText(text);
}
diff --git a/core/java/android/window/WindowInfosListenerForTest.java b/core/java/android/window/WindowInfosListenerForTest.java
index be88e53ad507..6e9f04482313 100644
--- a/core/java/android/window/WindowInfosListenerForTest.java
+++ b/core/java/android/window/WindowInfosListenerForTest.java
@@ -161,10 +161,8 @@ public class WindowInfosListenerForTest {
private static List<WindowInfo> buildWindowInfos(InputWindowHandle[] windowHandles) {
var windowInfos = new ArrayList<WindowInfo>(windowHandles.length);
for (var handle : windowHandles) {
- var bounds = new Rect(handle.frameLeft, handle.frameTop, handle.frameRight,
- handle.frameBottom);
windowInfos.add(new WindowInfo(handle.getWindowToken(), handle.name, handle.displayId,
- bounds, handle.inputConfig, handle.transform));
+ handle.frame, handle.inputConfig, handle.transform));
}
return windowInfos;
}
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
new file mode 100644
index 000000000000..560e41b1aa33
--- /dev/null
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.window.flags"
+
+# Project link: https://gantry.corp.google.com/projects/android_platform_windowing_sdk/changes
+
+flag {
+ namespace: "windowing_sdk"
+ name: "sync_window_config_update_flag"
+ description: "Whether the feature to sync different window-related config updates is enabled"
+ bug: "260873529"
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 79152b4b618f..d3103f1ed24b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -18,11 +18,10 @@ package com.android.internal.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStats.BitDescription;
-import android.os.BatteryStats.CpuUsageDetails;
-import android.os.BatteryStats.EnergyConsumerDetails;
import android.os.BatteryStats.HistoryItem;
import android.os.BatteryStats.HistoryStepDetails;
import android.os.BatteryStats.HistoryTag;
@@ -42,7 +41,6 @@ import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ParseUtils;
import java.io.File;
import java.io.FileOutputStream;
@@ -83,7 +81,7 @@ public class BatteryStatsHistory {
private static final int VERSION = 209;
private static final String HISTORY_DIR = "battery-history";
- private static final String FILE_SUFFIX = ".bin";
+ private static final String FILE_SUFFIX = ".bh";
private static final int MIN_FREE_SPACE = 100 * 1024 * 1024;
// Part of initial delta int that specifies the time delta.
@@ -124,10 +122,9 @@ public class BatteryStatsHistory {
// therefore the tag value is written in the parcel
static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000;
- static final int EXTENSION_MEASURED_ENERGY_HEADER_FLAG = 0x00000001;
- static final int EXTENSION_MEASURED_ENERGY_FLAG = 0x00000002;
- static final int EXTENSION_CPU_USAGE_HEADER_FLAG = 0x00000004;
- static final int EXTENSION_CPU_USAGE_FLAG = 0x00000008;
+ static final int EXTENSION_POWER_STATS_DESCRIPTOR_FLAG = 0x00000001;
+ static final int EXTENSION_POWER_STATS_FLAG = 0x00000002;
+ static final int EXTENSION_PROCESS_STATE_CHANGE_FLAG = 0x00000004;
// For state1, trace everything except the wakelock bit (which can race with
// suspend) and the running bit (which isn't meaningful in traces).
@@ -149,10 +146,11 @@ public class BatteryStatsHistory {
* The active history file that the history buffer is backed up into.
*/
private AtomicFile mActiveFile;
+
/**
- * A list of history files with incremental indexes.
+ * A list of history files with increasing timestamps.
*/
- private final List<Integer> mFileNumbers = new ArrayList<>();
+ private final List<BatteryHistoryFile> mHistoryFiles = new ArrayList<>();
/**
* A list of small history parcels, used when BatteryStatsImpl object is created from
@@ -200,14 +198,42 @@ public class BatteryStatsHistory {
private long mTrackRunningHistoryElapsedRealtimeMs = 0;
private long mTrackRunningHistoryUptimeMs = 0;
private long mHistoryBaseTimeMs;
- private boolean mMeasuredEnergyHeaderWritten = false;
- private boolean mCpuUsageHeaderWritten = false;
- private final VarintParceler mVarintParceler = new VarintParceler();
+ private final ArraySet<PowerStats.Descriptor> mWrittenPowerStatsDescriptors = new ArraySet<>();
private byte mLastHistoryStepLevel = 0;
private boolean mMutable = true;
private final BatteryStatsHistory mWritableHistory;
private boolean mCleanupEnabled = true;
+ private static class BatteryHistoryFile implements Comparable<BatteryHistoryFile> {
+ public final long monotonicTimeMs;
+ public final AtomicFile atomicFile;
+
+ private BatteryHistoryFile(File directory, long monotonicTimeMs) {
+ this.monotonicTimeMs = monotonicTimeMs;
+ atomicFile = new AtomicFile(new File(directory, monotonicTimeMs + FILE_SUFFIX));
+ }
+
+ @Override
+ public int compareTo(BatteryHistoryFile o) {
+ return Long.compare(monotonicTimeMs, o.monotonicTimeMs);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return monotonicTimeMs == ((BatteryHistoryFile) o).monotonicTimeMs;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(monotonicTimeMs);
+ }
+
+ @Override
+ public String toString() {
+ return atomicFile.getBaseFile().toString();
+ }
+ }
+
/**
* A delegate responsible for computing additional details for a step in battery history.
*/
@@ -317,32 +343,47 @@ public class BatteryStatsHistory {
Slog.wtf(TAG, "HistoryDir does not exist:" + mHistoryDir.getPath());
}
- final Set<Integer> dedup = new ArraySet<>();
- // scan directory, fill mFileNumbers and mActiveFile.
+ final List<File> toRemove = new ArrayList<>();
+ final Set<BatteryHistoryFile> dedup = new ArraySet<>();
mHistoryDir.listFiles((dir, name) -> {
final int b = name.lastIndexOf(FILE_SUFFIX);
if (b <= 0) {
+ toRemove.add(new File(dir, name));
return false;
}
- final int c = ParseUtils.parseInt(name.substring(0, b), -1);
- if (c != -1) {
- dedup.add(c);
- return true;
- } else {
+ try {
+ long monotonicTime = Long.parseLong(name.substring(0, b));
+ dedup.add(new BatteryHistoryFile(mHistoryDir, monotonicTime));
+ } catch (NumberFormatException e) {
+ toRemove.add(new File(dir, name));
return false;
}
+ return true;
});
if (!dedup.isEmpty()) {
- mFileNumbers.addAll(dedup);
- Collections.sort(mFileNumbers);
- setActiveFile(mFileNumbers.get(mFileNumbers.size() - 1));
- } else {
- // No file found, default to have file 0.
- mFileNumbers.add(0);
- setActiveFile(0);
+ mHistoryFiles.addAll(dedup);
+ Collections.sort(mHistoryFiles);
+ setActiveFile(mHistoryFiles.get(mHistoryFiles.size() - 1));
+ } else if (mMutable) {
+ // No file found, default to have the initial file.
+ BatteryHistoryFile name = makeBatteryHistoryFile();
+ mHistoryFiles.add(name);
+ setActiveFile(name);
+ }
+ if (!toRemove.isEmpty()) {
+ // Clear out legacy history files, which did not follow the X-Y.bin naming format.
+ BackgroundThread.getHandler().post(() -> {
+ for (File file : toRemove) {
+ file.delete();
+ }
+ });
}
}
+ private BatteryHistoryFile makeBatteryHistoryFile() {
+ return new BatteryHistoryFile(mHistoryDir, mClock.elapsedRealtime() + mHistoryBaseTimeMs);
+ }
+
public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
mMaxHistoryFiles = maxHistoryFiles;
@@ -384,8 +425,7 @@ public class BatteryStatsHistory {
mLastHistoryElapsedRealtimeMs = 0;
mTrackRunningHistoryElapsedRealtimeMs = 0;
mTrackRunningHistoryUptimeMs = 0;
- mMeasuredEnergyHeaderWritten = false;
- mCpuUsageHeaderWritten = false;
+ mWrittenPowerStatsDescriptors.clear();
mHistoryBuffer.setDataSize(0);
mHistoryBuffer.setDataPosition(0);
@@ -439,28 +479,15 @@ public class BatteryStatsHistory {
/**
* Set the active file that mHistoryBuffer is backed up into.
- *
- * @param fileNumber the history file that mHistoryBuffer is backed up into.
*/
- private void setActiveFile(int fileNumber) {
- mActiveFile = getFile(fileNumber);
+ private void setActiveFile(BatteryHistoryFile file) {
+ mActiveFile = file.atomicFile;
if (DEBUG) {
Slog.d(TAG, "activeHistoryFile:" + mActiveFile.getBaseFile().getPath());
}
}
/**
- * Create history AtomicFile from file number.
- *
- * @param num file number.
- * @return AtomicFile object.
- */
- private AtomicFile getFile(int num) {
- return new AtomicFile(
- new File(mHistoryDir, num + FILE_SUFFIX));
- }
-
- /**
* When {@link #mHistoryBuffer} reaches {@link BatteryStatsImpl.Constants#MAX_HISTORY_BUFFER},
* create next history file.
*/
@@ -470,15 +497,19 @@ public class BatteryStatsHistory {
return;
}
- if (mFileNumbers.isEmpty()) {
+ if (mHistoryFiles.isEmpty()) {
Slog.wtf(TAG, "mFileNumbers should never be empty");
return;
}
- // The last number in mFileNumbers is the highest number. The next file number is highest
- // number plus one.
- final int next = mFileNumbers.get(mFileNumbers.size() - 1) + 1;
- mFileNumbers.add(next);
+ final long start = SystemClock.uptimeMillis();
+ writeHistory();
+ if (DEBUG) {
+ Slog.d(TAG, "writeHistory took ms:" + (SystemClock.uptimeMillis() - start));
+ }
+
+ final BatteryHistoryFile next = makeBatteryHistoryFile();
+ mHistoryFiles.add(next);
setActiveFile(next);
try {
mActiveFile.getBaseFile().createNewFile();
@@ -486,6 +517,21 @@ public class BatteryStatsHistory {
Slog.e(TAG, "Could not create history file: " + mActiveFile.getBaseFile());
}
+ mHistoryBuffer.setDataSize(0);
+ mHistoryBuffer.setDataPosition(0);
+ mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2);
+ mHistoryBufferLastPos = -1;
+ mHistoryLastWritten.clear();
+ mHistoryLastLastWritten.clear();
+
+ // Mark every entry in the pool with a flag indicating that the tag
+ // has not yet been encountered while writing the current history buffer.
+ for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) {
+ entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG);
+ }
+
+ mWrittenPowerStatsDescriptors.clear();
+
synchronized (this) {
cleanupLocked();
}
@@ -507,17 +553,17 @@ public class BatteryStatsHistory {
// if free disk space is less than 100MB, delete oldest history file.
if (!hasFreeDiskSpace()) {
- int oldest = mFileNumbers.remove(0);
- getFile(oldest).delete();
+ BatteryHistoryFile oldest = mHistoryFiles.remove(0);
+ oldest.atomicFile.delete();
}
// if there are more history files than allowed, delete oldest history files.
// mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and can be updated by GService
// config at run time.
- while (mFileNumbers.size() > mMaxHistoryFiles) {
- int oldest = mFileNumbers.get(0);
- getFile(oldest).delete();
- mFileNumbers.remove(0);
+ while (mHistoryFiles.size() > mMaxHistoryFiles) {
+ BatteryHistoryFile oldest = mHistoryFiles.get(0);
+ oldest.atomicFile.delete();
+ mHistoryFiles.remove(0);
}
}
@@ -537,12 +583,14 @@ public class BatteryStatsHistory {
*/
public void reset() {
if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
- for (Integer i : mFileNumbers) {
- getFile(i).delete();
+ for (BatteryHistoryFile file : mHistoryFiles) {
+ file.atomicFile.delete();
}
- mFileNumbers.clear();
- mFileNumbers.add(0);
- setActiveFile(0);
+ mHistoryFiles.clear();
+
+ BatteryHistoryFile name = makeBatteryHistoryFile();
+ mHistoryFiles.add(name);
+ setActiveFile(name);
initHistoryBuffer();
}
@@ -550,9 +598,13 @@ public class BatteryStatsHistory {
/**
* Start iterating history files and history buffer.
*
- * @return always return true.
+ * @param startTimeMs monotonic time (the HistoryItem.time field) to start iterating from,
+ * inclusive
+ * @param endTimeMs monotonic time to stop iterating, exclusive.
+ * Pass 0 to indicate current time.
*/
- public BatteryStatsHistoryIterator iterate() {
+ @NonNull
+ public BatteryStatsHistoryIterator iterate(long startTimeMs, long endTimeMs) {
mCurrentFileIndex = 0;
mCurrentParcel = null;
mCurrentParcelEnd = 0;
@@ -563,7 +615,7 @@ public class BatteryStatsHistory {
mWritableHistory.setCleanupEnabledLocked(false);
}
}
- return new BatteryStatsHistoryIterator(this);
+ return new BatteryStatsHistoryIterator(this, startTimeMs, endTimeMs);
}
/**
@@ -590,7 +642,7 @@ public class BatteryStatsHistory {
* buffer
*/
@Nullable
- public Parcel getNextParcel() {
+ public Parcel getNextParcel(long startTimeMs, long endTimeMs) {
// First iterate through all records in current parcel.
if (mCurrentParcel != null) {
if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) {
@@ -606,13 +658,29 @@ public class BatteryStatsHistory {
}
}
- // Try next available history file.
+ int firstFileIndex = 0;
// skip the last file because its data is in history buffer.
- while (mCurrentFileIndex < mFileNumbers.size() - 1) {
+ int lastFileIndex = mHistoryFiles.size() - 1;
+ for (int i = mHistoryFiles.size() - 1; i >= 0; i--) {
+ BatteryHistoryFile file = mHistoryFiles.get(i);
+ if (file.monotonicTimeMs >= endTimeMs) {
+ lastFileIndex = i;
+ }
+ if (file.monotonicTimeMs <= startTimeMs) {
+ firstFileIndex = i;
+ break;
+ }
+ }
+
+ if (mCurrentFileIndex < firstFileIndex) {
+ mCurrentFileIndex = firstFileIndex;
+ }
+
+ while (mCurrentFileIndex < lastFileIndex) {
mCurrentParcel = null;
mCurrentParcelEnd = 0;
final Parcel p = Parcel.obtain();
- AtomicFile file = getFile(mFileNumbers.get(mCurrentFileIndex++));
+ AtomicFile file = mHistoryFiles.get(mCurrentFileIndex++).atomicFile;
if (readFileToParcel(p, file)) {
int bufSize = p.readInt();
int curPos = p.dataPosition();
@@ -769,9 +837,9 @@ public class BatteryStatsHistory {
private void writeToParcel(Parcel out, boolean useBlobs) {
final long start = SystemClock.uptimeMillis();
- out.writeInt(mFileNumbers.size() - 1);
- for (int i = 0; i < mFileNumbers.size() - 1; i++) {
- AtomicFile file = getFile(mFileNumbers.get(i));
+ out.writeInt(mHistoryFiles.size() - 1);
+ for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
+ AtomicFile file = mHistoryFiles.get(i).atomicFile;
byte[] raw = new byte[0];
try {
raw = file.readFully();
@@ -872,8 +940,12 @@ public class BatteryStatsHistory {
}
@VisibleForTesting
- public List<Integer> getFilesNumbers() {
- return mFileNumbers;
+ public List<String> getFilesNames() {
+ List<String> names = new ArrayList<>();
+ for (BatteryHistoryFile historyFile : mHistoryFiles) {
+ names.add(historyFile.atomicFile.getBaseFile().getName());
+ }
+ return names;
}
@VisibleForTesting
@@ -886,8 +958,8 @@ public class BatteryStatsHistory {
*/
public int getHistoryUsedSize() {
int ret = 0;
- for (int i = 0; i < mFileNumbers.size() - 1; i++) {
- ret += getFile(mFileNumbers.get(i)).getBaseFile().length();
+ for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
+ ret += mHistoryFiles.get(i).atomicFile.getBaseFile().length();
}
ret += mHistoryBuffer.dataSize();
if (mHistoryParcels != null) {
@@ -937,7 +1009,7 @@ public class BatteryStatsHistory {
* Prepares to continue recording after restoring previous history from persistent storage.
*/
public void continueRecordingHistory() {
- if (mHistoryBuffer.dataPosition() <= 0 && mFileNumbers.size() <= 1) {
+ if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
return;
}
@@ -1050,11 +1122,23 @@ public class BatteryStatsHistory {
}
/**
- * Records measured energy data.
+ * Records a PowerStats snapshot.
*/
- public void recordEnergyConsumerDetails(long elapsedRealtimeMs, long uptimeMs,
- EnergyConsumerDetails energyConsumerDetails) {
- mHistoryCur.energyConsumerDetails = energyConsumerDetails;
+ public void recordPowerStats(long elapsedRealtimeMs, long uptimeMs,
+ PowerStats powerStats) {
+ mHistoryCur.powerStats = powerStats;
+ mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
+
+ /**
+ * Records the change of a UID's proc state.
+ */
+ public void recordProcessStateChange(long elapsedRealtimeMs, long uptimeMs,
+ int uid, @BatteryConsumer.ProcessState int processState) {
+ mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
+ mHistoryCur.processStateChange.uid = uid;
+ mHistoryCur.processStateChange.processState = processState;
mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1279,17 +1363,6 @@ public class BatteryStatsHistory {
}
/**
- * Records CPU usage by a specific UID. The recorded data is the delta from
- * the previous record for the same UID.
- */
- public void recordCpuUsage(long elapsedRealtimeMs, long uptimeMs,
- CpuUsageDetails cpuUsageDetails) {
- mHistoryCur.cpuUsageDetails = cpuUsageDetails;
- mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
- }
-
- /**
* Writes changes to a HistoryItem state bitmap to Atrace.
*/
private void recordTraceCounters(int oldval, int newval, int mask,
@@ -1355,7 +1428,9 @@ public class BatteryStatsHistory {
mTraceLastState2 = cur.states2;
}
- if (!mHaveBatteryLevel || !mRecordingHistory) {
+ if ((!mHaveBatteryLevel || !mRecordingHistory)
+ && cur.powerStats == null
+ && cur.processStateChange == null) {
return;
}
@@ -1391,8 +1466,8 @@ public class BatteryStatsHistory {
&& mHistoryLastWritten.batteryPlugType == cur.batteryPlugType
&& mHistoryLastWritten.batteryTemperature == cur.batteryTemperature
&& mHistoryLastWritten.batteryVoltage == cur.batteryVoltage
- && mHistoryLastWritten.energyConsumerDetails == null
- && mHistoryLastWritten.cpuUsageDetails == null) {
+ && mHistoryLastWritten.powerStats == null
+ && mHistoryLastWritten.processStateChange == null) {
// We can merge this new change in with the last one. Merging is
// allowed as long as only the states have changed, and within those states
// as long as no bit has changed both between now and the last entry, as
@@ -1434,34 +1509,15 @@ public class BatteryStatsHistory {
mMaxHistoryBufferSize = 1024;
}
- //open a new history file.
- final long start = SystemClock.uptimeMillis();
- writeHistory();
- if (DEBUG) {
- Slog.d(TAG, "addHistoryBufferLocked writeHistory took ms:"
- + (SystemClock.uptimeMillis() - start));
- }
- startNextFile();
- mHistoryBuffer.setDataSize(0);
- mHistoryBuffer.setDataPosition(0);
- mHistoryBuffer.setDataCapacity(mMaxHistoryBufferSize / 2);
- mHistoryBufferLastPos = -1;
- mHistoryLastWritten.clear();
- mHistoryLastLastWritten.clear();
-
- // Mark every entry in the pool with a flag indicating that the tag
- // has not yet been encountered while writing the current history buffer.
- for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) {
- entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG);
- }
- mMeasuredEnergyHeaderWritten = false;
- mCpuUsageHeaderWritten = false;
-
// Make a copy of mHistoryCur.
HistoryItem copy = new HistoryItem();
copy.setTo(cur);
+
+ startNextFile();
+
// startRecordingHistory will reset mHistoryCur.
startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
+
// Add the copy into history buffer.
writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_UPDATE);
return;
@@ -1477,8 +1533,8 @@ public class BatteryStatsHistory {
copy.eventCode = HistoryItem.EVENT_NONE;
copy.eventTag = null;
copy.tagsFirstOccurrence = false;
- copy.energyConsumerDetails = null;
- copy.cpuUsageDetails = null;
+ copy.powerStats = null;
+ copy.processStateChange = null;
writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_RESET);
}
writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE);
@@ -1506,8 +1562,8 @@ public class BatteryStatsHistory {
cur.eventCode = HistoryItem.EVENT_NONE;
cur.eventTag = null;
cur.tagsFirstOccurrence = false;
- cur.energyConsumerDetails = null;
- cur.cpuUsageDetails = null;
+ cur.powerStats = null;
+ cur.processStateChange = null;
if (DEBUG) {
Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+ " now " + mHistoryBuffer.dataPosition()
@@ -1638,17 +1694,14 @@ public class BatteryStatsHistory {
if (stateIntChanged) {
firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG;
}
- if (cur.energyConsumerDetails != null) {
- extensionFlags |= BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_FLAG;
- if (!mMeasuredEnergyHeaderWritten) {
- extensionFlags |= BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_HEADER_FLAG;
+ if (cur.powerStats != null) {
+ extensionFlags |= BatteryStatsHistory.EXTENSION_POWER_STATS_FLAG;
+ if (!mWrittenPowerStatsDescriptors.contains(cur.powerStats.descriptor)) {
+ extensionFlags |= BatteryStatsHistory.EXTENSION_POWER_STATS_DESCRIPTOR_FLAG;
}
}
- if (cur.cpuUsageDetails != null) {
- extensionFlags |= EXTENSION_CPU_USAGE_FLAG;
- if (!mCpuUsageHeaderWritten) {
- extensionFlags |= BatteryStatsHistory.EXTENSION_CPU_USAGE_HEADER_FLAG;
- }
+ if (cur.processStateChange != null) {
+ extensionFlags |= BatteryStatsHistory.EXTENSION_PROCESS_STATE_CHANGE_FLAG;
}
if (extensionFlags != 0) {
cur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
@@ -1773,37 +1826,16 @@ public class BatteryStatsHistory {
dest.writeDouble(cur.wifiRailChargeMah);
if (extensionFlags != 0) {
dest.writeInt(extensionFlags);
- if (cur.energyConsumerDetails != null) {
- if (DEBUG) {
- Slog.i(TAG, "WRITE DELTA: measuredEnergyDetails=" + cur.energyConsumerDetails);
- }
- if (!mMeasuredEnergyHeaderWritten) {
- EnergyConsumerDetails.EnergyConsumer[] consumers =
- cur.energyConsumerDetails.consumers;
- dest.writeInt(consumers.length);
- for (EnergyConsumerDetails.EnergyConsumer consumer : consumers) {
- dest.writeInt(consumer.type);
- dest.writeInt(consumer.ordinal);
- dest.writeString(consumer.name);
- }
- mMeasuredEnergyHeaderWritten = true;
+ if (cur.powerStats != null) {
+ if ((extensionFlags & BatteryStatsHistory.EXTENSION_POWER_STATS_DESCRIPTOR_FLAG)
+ != 0) {
+ cur.powerStats.descriptor.writeSummaryToParcel(dest);
+ mWrittenPowerStatsDescriptors.add(cur.powerStats.descriptor);
}
- mVarintParceler.writeLongArray(dest, cur.energyConsumerDetails.chargeUC);
+ cur.powerStats.writeToParcel(dest);
}
-
- if (cur.cpuUsageDetails != null) {
- if (DEBUG) {
- Slog.i(TAG, "WRITE DELTA: cpuUsageDetails=" + cur.cpuUsageDetails);
- }
- if (!mCpuUsageHeaderWritten) {
- dest.writeInt(cur.cpuUsageDetails.cpuBracketDescriptions.length);
- for (String desc: cur.cpuUsageDetails.cpuBracketDescriptions) {
- dest.writeString(desc);
- }
- mCpuUsageHeaderWritten = true;
- }
- dest.writeInt(cur.cpuUsageDetails.uid);
- mVarintParceler.writeLongArray(dest, cur.cpuUsageDetails.cpuUsageMs);
+ if (cur.processStateChange != null) {
+ cur.processStateChange.writeToParcel(dest);
}
}
}
@@ -2054,13 +2086,15 @@ public class BatteryStatsHistory {
* fewer bytes. It is a bit more expensive than just writing the long into the parcel,
* but at scale saves a lot of storage and allows recording of longer battery history.
*/
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static final class VarintParceler {
/**
* Writes an array of longs into Parcel using the varint format, see
* https://developers.google.com/protocol-buffers/docs/encoding#varints
*/
public void writeLongArray(Parcel parcel, long[] values) {
+ if (values.length == 0) {
+ return;
+ }
int out = 0;
int shift = 0;
for (long value : values) {
@@ -2092,6 +2126,9 @@ public class BatteryStatsHistory {
* Reads a long written with {@link #writeLongArray}
*/
public void readLongArray(Parcel parcel, long[] values) {
+ if (values.length == 0) {
+ return;
+ }
int in = parcel.readInt();
int available = 4;
for (int i = 0; i < values.length; i++) {
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index 4c2b2854df88..a5d2d0fc1a01 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
import android.os.BatteryManager;
import android.os.BatteryStats;
@@ -33,32 +34,32 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
private static final boolean DEBUG = false;
private static final String TAG = "BatteryStatsHistoryItr";
private final BatteryStatsHistory mBatteryStatsHistory;
+ private final @CurrentTimeMillisLong long mStartTimeMs;
+ private final @CurrentTimeMillisLong long mEndTimeMs;
private final BatteryStats.HistoryStepDetails mReadHistoryStepDetails =
new BatteryStats.HistoryStepDetails();
private final SparseArray<BatteryStats.HistoryTag> mHistoryTags = new SparseArray<>();
- private BatteryStats.EnergyConsumerDetails mEnergyConsumerDetails;
- private BatteryStats.CpuUsageDetails mCpuUsageDetails;
- private final BatteryStatsHistory.VarintParceler mVarintParceler =
- new BatteryStatsHistory.VarintParceler();
+ private final PowerStats.DescriptorRegistry mDescriptorRegistry =
+ new PowerStats.DescriptorRegistry();
+ private BatteryStats.HistoryItem mHistoryItem = new BatteryStats.HistoryItem();
+ private boolean mNextItemReady;
- private final BatteryStats.HistoryItem mHistoryItem = new BatteryStats.HistoryItem();
-
- private static final int MAX_ENERGY_CONSUMER_COUNT = 100;
- private static final int MAX_CPU_BRACKET_COUNT = 100;
-
- public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history) {
+ public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
+ @CurrentTimeMillisLong long startTimeMs,
+ @CurrentTimeMillisLong long endTimeMs) {
mBatteryStatsHistory = history;
+ mStartTimeMs = startTimeMs;
+ mEndTimeMs = (endTimeMs != 0) ? endTimeMs : Long.MAX_VALUE;
mHistoryItem.clear();
}
@Override
public boolean hasNext() {
- Parcel p = mBatteryStatsHistory.getNextParcel();
- if (p == null) {
- close();
- return false;
+ if (!mNextItemReady) {
+ advance();
}
- return true;
+
+ return mHistoryItem != null;
}
/**
@@ -67,25 +68,45 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
*/
@Override
public BatteryStats.HistoryItem next() {
- Parcel p = mBatteryStatsHistory.getNextParcel();
- if (p == null) {
- close();
- return null;
+ if (!mNextItemReady) {
+ advance();
}
+ mNextItemReady = false;
+ return mHistoryItem;
+ }
- final long lastRealtimeMs = mHistoryItem.time;
- final long lastWalltimeMs = mHistoryItem.currentTime;
- try {
- readHistoryDelta(p, mHistoryItem);
- } catch (Throwable t) {
- Slog.wtf(TAG, "Corrupted battery history", t);
- return null;
- }
- if (mHistoryItem.cmd != BatteryStats.HistoryItem.CMD_CURRENT_TIME
- && mHistoryItem.cmd != BatteryStats.HistoryItem.CMD_RESET && lastWalltimeMs != 0) {
- mHistoryItem.currentTime = lastWalltimeMs + (mHistoryItem.time - lastRealtimeMs);
+ private void advance() {
+ while (true) {
+ Parcel p = mBatteryStatsHistory.getNextParcel(mStartTimeMs, mEndTimeMs);
+ if (p == null) {
+ break;
+ }
+
+ final long lastRealtimeMs = mHistoryItem.time;
+ final long lastWalltimeMs = mHistoryItem.currentTime;
+ try {
+ readHistoryDelta(p, mHistoryItem);
+ } catch (Throwable t) {
+ Slog.wtf(TAG, "Corrupted battery history", t);
+ break;
+ }
+ if (mHistoryItem.cmd != BatteryStats.HistoryItem.CMD_CURRENT_TIME
+ && mHistoryItem.cmd != BatteryStats.HistoryItem.CMD_RESET
+ && lastWalltimeMs != 0) {
+ mHistoryItem.currentTime = lastWalltimeMs + (mHistoryItem.time - lastRealtimeMs);
+ }
+ if (mEndTimeMs != 0 && mHistoryItem.currentTime >= mEndTimeMs) {
+ break;
+ }
+ if (mHistoryItem.currentTime >= mStartTimeMs) {
+ mNextItemReady = true;
+ return;
+ }
}
- return mHistoryItem;
+
+ mHistoryItem = null;
+ mNextItemReady = true;
+ close();
}
private void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) {
@@ -229,74 +250,24 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
cur.wifiRailChargeMah = src.readDouble();
if ((cur.states2 & BatteryStats.HistoryItem.STATE2_EXTENSIONS_FLAG) != 0) {
final int extensionFlags = src.readInt();
- if ((extensionFlags & BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_HEADER_FLAG) != 0) {
- if (mEnergyConsumerDetails == null) {
- mEnergyConsumerDetails = new BatteryStats.EnergyConsumerDetails();
- }
-
- final int consumerCount = src.readInt();
- if (consumerCount > MAX_ENERGY_CONSUMER_COUNT) {
- // Check to avoid a heap explosion in case the parcel is corrupted
- throw new IllegalStateException(
- "EnergyConsumer count too high: " + consumerCount
- + ". Max = " + MAX_ENERGY_CONSUMER_COUNT);
- }
- mEnergyConsumerDetails.consumers =
- new BatteryStats.EnergyConsumerDetails.EnergyConsumer[consumerCount];
- mEnergyConsumerDetails.chargeUC = new long[consumerCount];
- for (int i = 0; i < consumerCount; i++) {
- BatteryStats.EnergyConsumerDetails.EnergyConsumer consumer =
- new BatteryStats.EnergyConsumerDetails.EnergyConsumer();
- consumer.type = src.readInt();
- consumer.ordinal = src.readInt();
- consumer.name = src.readString();
- mEnergyConsumerDetails.consumers[i] = consumer;
- }
+ if ((extensionFlags & BatteryStatsHistory.EXTENSION_POWER_STATS_DESCRIPTOR_FLAG) != 0) {
+ PowerStats.Descriptor descriptor = PowerStats.Descriptor.readSummaryFromParcel(src);
+ mDescriptorRegistry.register(descriptor);
}
-
- if ((extensionFlags & BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_FLAG) != 0) {
- if (mEnergyConsumerDetails == null) {
- throw new IllegalStateException("MeasuredEnergyDetails without a header");
- }
-
- mVarintParceler.readLongArray(src, mEnergyConsumerDetails.chargeUC);
- cur.energyConsumerDetails = mEnergyConsumerDetails;
+ if ((extensionFlags & BatteryStatsHistory.EXTENSION_POWER_STATS_FLAG) != 0) {
+ cur.powerStats = PowerStats.readFromParcel(src, mDescriptorRegistry);
} else {
- cur.energyConsumerDetails = null;
- }
-
- if ((extensionFlags & BatteryStatsHistory.EXTENSION_CPU_USAGE_HEADER_FLAG) != 0) {
- mCpuUsageDetails = new BatteryStats.CpuUsageDetails();
- final int cpuBracketCount = src.readInt();
- if (cpuBracketCount > MAX_CPU_BRACKET_COUNT) {
- // Check to avoid a heap explosion in case the parcel is corrupted
- throw new IllegalStateException("Too many CPU brackets: " + cpuBracketCount
- + ". Max = " + MAX_CPU_BRACKET_COUNT);
- }
- mCpuUsageDetails.cpuBracketDescriptions = new String[cpuBracketCount];
- for (int i = 0; i < cpuBracketCount; i++) {
- mCpuUsageDetails.cpuBracketDescriptions[i] = src.readString();
- }
- mCpuUsageDetails.cpuUsageMs =
- new long[mCpuUsageDetails.cpuBracketDescriptions.length];
- } else if (mCpuUsageDetails != null) {
- mCpuUsageDetails.cpuBracketDescriptions = null;
+ cur.powerStats = null;
}
-
- if ((extensionFlags & BatteryStatsHistory.EXTENSION_CPU_USAGE_FLAG) != 0) {
- if (mCpuUsageDetails == null) {
- throw new IllegalStateException("CpuUsageDetails without a header");
- }
-
- mCpuUsageDetails.uid = src.readInt();
- mVarintParceler.readLongArray(src, mCpuUsageDetails.cpuUsageMs);
- cur.cpuUsageDetails = mCpuUsageDetails;
+ if ((extensionFlags & BatteryStatsHistory.EXTENSION_PROCESS_STATE_CHANGE_FLAG) != 0) {
+ cur.processStateChange = cur.localProcessStateChange;
+ cur.processStateChange.readFromParcel(src);
} else {
- cur.cpuUsageDetails = null;
+ cur.processStateChange = null;
}
} else {
- cur.energyConsumerDetails = null;
- cur.cpuUsageDetails = null;
+ cur.powerStats = null;
+ cur.processStateChange = null;
}
}
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index 664aeee6e299..5ea6ba86da71 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -195,6 +195,34 @@ public final class LongArrayMultiStateCounter implements Parcelable {
* is distributed among the state according to the time the object spent in those states
* since the previous call to updateValues.
*/
+ public void updateValues(long[] values, long timestampMs) {
+ LongArrayContainer container = sTmpArrayContainer.getAndSet(null);
+ if (container == null || container.mLength != values.length) {
+ container = new LongArrayContainer(values.length);
+ }
+ container.setValues(values);
+ updateValues(container, timestampMs);
+ sTmpArrayContainer.set(container);
+ }
+
+ /**
+ * Adds the supplied values to the current accumulated values in the counter.
+ */
+ public void incrementValues(long[] values, long timestampMs) {
+ LongArrayContainer container = sTmpArrayContainer.getAndSet(null);
+ if (container == null || container.mLength != values.length) {
+ container = new LongArrayContainer(values.length);
+ }
+ container.setValues(values);
+ native_incrementValues(mNativeObject, container.mNativeObject, timestampMs);
+ sTmpArrayContainer.set(container);
+ }
+
+ /**
+ * Sets the new values. The delta between the previously set values and these values
+ * is distributed among the state according to the time the object spent in those states
+ * since the previous call to updateValues.
+ */
public void updateValues(LongArrayContainer longArrayContainer, long timestampMs) {
if (longArrayContainer.mLength != mLength) {
throw new IllegalArgumentException(
@@ -293,6 +321,10 @@ public final class LongArrayMultiStateCounter implements Parcelable {
long longArrayContainerNativeObject, long timestampMs);
@CriticalNative
+ private static native void native_incrementValues(long nativeObject,
+ long longArrayContainerNativeObject, long timestampMs);
+
+ @CriticalNative
private static native void native_addCounts(long nativeObject,
long longArrayContainerNativeObject);
diff --git a/core/java/com/android/internal/os/MultiStateStats.java b/core/java/com/android/internal/os/MultiStateStats.java
new file mode 100644
index 000000000000..f971849987dd
--- /dev/null
+++ b/core/java/com/android/internal/os/MultiStateStats.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Maintains multidimensional multi-state stats. States could be something like on-battery (0,1),
+ * screen-on (0,1), process state etc. Dimensions refer to the metrics themselves, e.g.
+ * CPU residency, Network packet counts etc. All metrics must be represented as <code>long</code>
+ * values;
+ */
+public class MultiStateStats {
+ /**
+ * A set of states, e.g. on-battery, screen-on, procstate. The state values are integers
+ * from 0 to States.mLabels.length
+ */
+ public static class States {
+ final boolean mTracked;
+ final String[] mLabels;
+
+ public States(boolean tracked, String... labels) {
+ this.mTracked = tracked;
+ this.mLabels = labels;
+ }
+
+ public boolean isTracked() {
+ return mTracked;
+ }
+ }
+
+ /**
+ * Factory for MultiStateStats containers. All generated containers retain their connection
+ * to the Factory and the corresponding configuration.
+ */
+ public static class Factory {
+ private static final int INVALID_SERIAL_STATE = -1;
+ final int mDimensionCount;
+ final States[] mStates;
+ /*
+ * The LongArrayMultiStateCounter object that is used for accumulation of per-state
+ * stats thinks of "state" as a simple 0-based index. This Factory object's job is to
+ * map a combination of individual states (e.g. on-battery, process state etc) to
+ * such a simple index.
+ *
+ * This task is performed in two steps:
+ * 1) We define "composite state" as an integer that combines all constituent States
+ * into one integer as bit fields. This gives us a convenient mechanism for updating a
+ * single constituent State at a time. We maintain an array of bit field masks
+ * corresponding to each constituent State.
+ *
+ * 2) We map composite states to "serial states", i.e. simple integer indexes, taking
+ * into account which constituent states are configured as tracked. If a state is not
+ * tracked, there is no need to maintain separate counts for its values, thus
+ * all values of that constituent state can be mapped to the same serial state.
+ */
+ private final int[] mStateBitFieldMasks;
+ private final short[] mStateBitFieldShifts;
+ final int[] mCompositeToSerialState;
+ final int mSerialStateCount;
+
+ public Factory(int dimensionCount, States... states) {
+ mDimensionCount = dimensionCount;
+ mStates = states;
+
+ int serialStateCount = 1;
+ for (States state : mStates) {
+ if (state.mTracked) {
+ serialStateCount *= state.mLabels.length;
+ }
+ }
+ mSerialStateCount = serialStateCount;
+
+ mStateBitFieldMasks = new int[mStates.length];
+ mStateBitFieldShifts = new short[mStates.length];
+
+ int shift = 0;
+ for (int i = 0; i < mStates.length; i++) {
+ mStateBitFieldShifts[i] = (short) shift;
+ if (mStates[i].mLabels.length < 2) {
+ throw new IllegalArgumentException("Invalid state: " + Arrays.toString(
+ mStates[i].mLabels) + ". Should have at least two values.");
+ }
+ int max = mStates[i].mLabels.length - 1;
+ int bitcount = Integer.SIZE - Integer.numberOfLeadingZeros(max);
+ mStateBitFieldMasks[i] = ((1 << bitcount) - 1) << shift;
+ shift = shift + bitcount;
+ }
+
+ if (shift >= Integer.SIZE - 1) {
+ throw new IllegalArgumentException("Too many states: " + shift
+ + " bits are required to represent the composite state, but only "
+ + (Integer.SIZE - 1) + " are available");
+ }
+
+ // Create a mask that filters out all non tracked states
+ int trackedMask = 0xFFFFFFFF;
+ for (int state = 0; state < mStates.length; state++) {
+ if (!mStates[state].mTracked) {
+ trackedMask &= ~mStateBitFieldMasks[state];
+ }
+ }
+
+ mCompositeToSerialState = new int[1 << shift];
+ Arrays.fill(mCompositeToSerialState, INVALID_SERIAL_STATE);
+
+ int nextSerialState = 0;
+ for (int composite = 0; composite < mCompositeToSerialState.length; composite++) {
+ if (!isValidCompositeState(composite)) continue;
+
+ // Values of an untracked State map to different composite states, but must map to
+ // the same serial state. Achieve that by computing a "base composite", which
+ // is equivalent to the current composite, but has 0 for all untracked States.
+ // See if the base composite already has a serial state assigned. If so, just use
+ // the same one for the current composite.
+ int baseComposite = composite & trackedMask;
+ if (mCompositeToSerialState[baseComposite] != INVALID_SERIAL_STATE) {
+ mCompositeToSerialState[composite] = mCompositeToSerialState[baseComposite];
+ } else {
+ mCompositeToSerialState[composite] = nextSerialState++;
+ }
+ }
+ }
+
+ private boolean isValidCompositeState(int composite) {
+ for (int stateIndex = 0; stateIndex < mStates.length; stateIndex++) {
+ int state = extractStateFromComposite(composite, stateIndex);
+ if (state >= mStates[stateIndex].mLabels.length) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private int extractStateFromComposite(int compositeState, int stateIndex) {
+ return (compositeState & mStateBitFieldMasks[stateIndex])
+ >>> mStateBitFieldShifts[stateIndex];
+ }
+
+ private int setStateInComposite(int baseCompositeState, int stateIndex, int value) {
+ return (baseCompositeState & ~mStateBitFieldMasks[stateIndex])
+ | (value << mStateBitFieldShifts[stateIndex]);
+ }
+
+ /**
+ * Allocates a new stats container using this Factory's configuration.
+ */
+ public MultiStateStats create() {
+ return new MultiStateStats(this, mDimensionCount);
+ }
+
+ /**
+ * Returns the total number of composite states handled by this container. For example,
+ * if there are two states: on-battery (0,1) and screen-on (0,1), both tracked, then the
+ * serial state count will be 2 * 2 = 4
+ */
+ @VisibleForTesting
+ public int getSerialStateCount() {
+ return mSerialStateCount;
+ }
+
+ /**
+ * Returns the integer index used by this container to represent the supplied composite
+ * state.
+ */
+ @VisibleForTesting
+ public int getSerialState(int[] states) {
+ Preconditions.checkArgument(states.length == mStates.length);
+ int compositeState = 0;
+ for (int i = 0; i < states.length; i++) {
+ compositeState = setStateInComposite(compositeState, i, states[i]);
+ }
+ int serialState = mCompositeToSerialState[compositeState];
+ if (serialState == INVALID_SERIAL_STATE) {
+ throw new IllegalArgumentException("State values out of bounds: "
+ + Arrays.toString(states));
+ }
+ return serialState;
+ }
+ }
+
+ private final Factory mFactory;
+ private final LongArrayMultiStateCounter mCounter;
+ private int mCompositeState;
+ private boolean mTracking;
+
+ public MultiStateStats(Factory factory, int dimensionCount) {
+ this.mFactory = factory;
+ mCounter = new LongArrayMultiStateCounter(factory.mSerialStateCount, dimensionCount);
+ }
+
+ /**
+ * Updates the current composite state by changing one of the States supplied to the Factory
+ * constructor.
+ *
+ * @param stateIndex Corresponds to the index of the States supplied to the Factory constructor
+ * @param state The new value of the state (e.g. 0 or 1 for "on-battery")
+ * @param timestampMs The time when the state change occurred
+ */
+ public void setState(int stateIndex, int state, long timestampMs) {
+ if (!mTracking) {
+ mCounter.updateValues(new long[mCounter.getArrayLength()], timestampMs);
+ mTracking = true;
+ }
+ mCompositeState = mFactory.setStateInComposite(mCompositeState, stateIndex, state);
+ mCounter.setState(mFactory.mCompositeToSerialState[mCompositeState], timestampMs);
+ }
+
+ /**
+ * Adds the delta to the metrics. The number of values must correspond to the dimension count
+ * supplied to the Factory constructor
+ */
+ public void increment(long[] values, long timestampMs) {
+ mCounter.incrementValues(values, timestampMs);
+ mTracking = true;
+ }
+
+ /**
+ * Returns accumulated stats for the specified composite state.
+ */
+ public void getStats(long[] outValues, int[] states) {
+ mCounter.getCounts(outValues, mFactory.getSerialState(states));
+ }
+
+ /**
+ * Resets the counters.
+ */
+ public void reset() {
+ mCounter.reset();
+ mTracking = false;
+ }
+
+ @Override
+ public String toString() {
+ return mCounter.toString();
+ }
+
+ /**
+ * Prints the accumulated stats, one line of every combination of states that has data.
+ */
+ public void dump(PrintWriter pw) {
+ long[] tmpArray = new long[mCounter.getArrayLength()];
+ dumpAllStates(pw, new int[mFactory.mStates.length], 0, tmpArray);
+ }
+
+ private void dumpAllStates(PrintWriter pw, int[] states, int stateIndex, long[] values) {
+ if (stateIndex < states.length) {
+ if (!mFactory.mStates[stateIndex].mTracked) {
+ dumpAllStates(pw, states, stateIndex + 1, values);
+ return;
+ }
+
+ for (int i = 0; i < mFactory.mStates[stateIndex].mLabels.length; i++) {
+ states[stateIndex] = i;
+ dumpAllStates(pw, states, stateIndex + 1, values);
+ }
+ return;
+ }
+
+ mCounter.getCounts(values, mFactory.getSerialState(states));
+ boolean nonZero = false;
+ for (long value : values) {
+ if (value != 0) {
+ nonZero = true;
+ break;
+ }
+ }
+ if (!nonZero) {
+ return;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < states.length; i++) {
+ if (mFactory.mStates[i].mTracked) {
+ if (sb.length() != 0) {
+ sb.append(" ");
+ }
+ sb.append(mFactory.mStates[i].mLabels[states[i]]);
+ }
+ }
+ sb.append(" ");
+ sb.append(Arrays.toString(values));
+ pw.println(sb);
+ }
+}
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 0b9773e2c907..e35b7f184663 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -11,6 +11,7 @@ per-file BatteryUsageStats* = file:/BATTERY_STATS_OWNERS
per-file *ChargeCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerEstimator* = file:/BATTERY_STATS_OWNERS
+per-file *PowerStats* = file:/BATTERY_STATS_OWNERS
per-file *Kernel* = file:/BATTERY_STATS_OWNERS
per-file *MultiState* = file:/BATTERY_STATS_OWNERS
per-file *PowerProfile* = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java
new file mode 100644
index 000000000000..8f66d1f9365c
--- /dev/null
+++ b/core/java/com/android/internal/os/PowerStats.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.BatteryConsumer;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Container for power stats, acquired by various PowerStatsCollector classes. See subclasses for
+ * details.
+ */
+public final class PowerStats {
+ private static final String TAG = "PowerStats";
+
+ private static final BatteryStatsHistory.VarintParceler VARINT_PARCELER =
+ new BatteryStatsHistory.VarintParceler();
+ private static final byte PARCEL_FORMAT_VERSION = 1;
+
+ private static final int PARCEL_FORMAT_VERSION_MASK = 0x000000FF;
+ private static final int PARCEL_FORMAT_VERSION_SHIFT =
+ Integer.numberOfTrailingZeros(PARCEL_FORMAT_VERSION_MASK);
+ private static final int STATS_ARRAY_LENGTH_MASK = 0x0000FF00;
+ private static final int STATS_ARRAY_LENGTH_SHIFT =
+ Integer.numberOfTrailingZeros(STATS_ARRAY_LENGTH_MASK);
+ public static final int MAX_STATS_ARRAY_LENGTH =
+ 2 ^ Integer.bitCount(STATS_ARRAY_LENGTH_MASK) - 1;
+ private static final int UID_STATS_ARRAY_LENGTH_MASK = 0x00FF0000;
+ private static final int UID_STATS_ARRAY_LENGTH_SHIFT =
+ Integer.numberOfTrailingZeros(UID_STATS_ARRAY_LENGTH_MASK);
+ public static final int MAX_UID_STATS_ARRAY_LENGTH =
+ (2 ^ Integer.bitCount(UID_STATS_ARRAY_LENGTH_MASK)) - 1;
+
+ /**
+ * Descriptor of the stats collected for a given power component (e.g. CPU, WiFi etc).
+ * This descriptor is used for storing PowerStats and can also be used by power models
+ * to adjust the algorithm in accordance with the stats available on the device.
+ */
+ public static class Descriptor {
+ /**
+ * {@link BatteryConsumer.PowerComponent} (e.g. CPU, WIFI etc) that this snapshot relates
+ * to; or a custom power component ID (if the value
+ * is &gt;= {@link BatteryConsumer#FIRST_CUSTOM_POWER_COMPONENT_ID}).
+ */
+ public final int powerComponentId;
+ public final String name;
+
+ public final int statsArrayLength;
+ public final int uidStatsArrayLength;
+
+ /**
+ * Extra parameters specific to the power component, e.g. the availability of power
+ * monitors.
+ */
+ public final PersistableBundle extras;
+
+ public Descriptor(@BatteryConsumer.PowerComponent int powerComponentId,
+ int statsArrayLength, int uidStatsArrayLength, @NonNull PersistableBundle extras) {
+ this(powerComponentId, BatteryConsumer.powerComponentIdToString(powerComponentId),
+ statsArrayLength, uidStatsArrayLength, extras);
+ }
+
+ public Descriptor(int customPowerComponentId, String name, int statsArrayLength,
+ int uidStatsArrayLength, PersistableBundle extras) {
+ if (statsArrayLength > MAX_STATS_ARRAY_LENGTH) {
+ throw new IllegalArgumentException(
+ "statsArrayLength is too high. Max = " + MAX_STATS_ARRAY_LENGTH);
+ }
+ if (uidStatsArrayLength > MAX_UID_STATS_ARRAY_LENGTH) {
+ throw new IllegalArgumentException(
+ "uidStatsArrayLength is too high. Max = " + MAX_UID_STATS_ARRAY_LENGTH);
+ }
+ this.powerComponentId = customPowerComponentId;
+ this.name = name;
+ this.statsArrayLength = statsArrayLength;
+ this.uidStatsArrayLength = uidStatsArrayLength;
+ this.extras = extras;
+ }
+
+ /**
+ * Writes the Descriptor into the parcel.
+ */
+ public void writeSummaryToParcel(Parcel parcel) {
+ int firstWord = ((PARCEL_FORMAT_VERSION << PARCEL_FORMAT_VERSION_SHIFT)
+ & PARCEL_FORMAT_VERSION_MASK)
+ | ((statsArrayLength << STATS_ARRAY_LENGTH_SHIFT)
+ & STATS_ARRAY_LENGTH_MASK)
+ | ((uidStatsArrayLength << UID_STATS_ARRAY_LENGTH_SHIFT)
+ & UID_STATS_ARRAY_LENGTH_MASK);
+ parcel.writeInt(firstWord);
+ parcel.writeInt(powerComponentId);
+ parcel.writeString(name);
+ extras.writeToParcel(parcel, 0);
+ }
+
+ /**
+ * Reads a Descriptor from the parcel. If the parcel has an incompatible format,
+ * returns null.
+ */
+ @Nullable
+ public static Descriptor readSummaryFromParcel(Parcel parcel) {
+ int firstWord = parcel.readInt();
+ int version = (firstWord & PARCEL_FORMAT_VERSION_MASK) >>> PARCEL_FORMAT_VERSION_SHIFT;
+ if (version != PARCEL_FORMAT_VERSION) {
+ Log.w(TAG, "Cannot read PowerStats from Parcel - the parcel format version has "
+ + "changed from " + version + " to " + PARCEL_FORMAT_VERSION);
+ return null;
+ }
+ int statsArrayLength =
+ (firstWord & STATS_ARRAY_LENGTH_MASK) >>> STATS_ARRAY_LENGTH_SHIFT;
+ int uidStatsArrayLength =
+ (firstWord & UID_STATS_ARRAY_LENGTH_MASK) >>> UID_STATS_ARRAY_LENGTH_SHIFT;
+ int powerComponentId = parcel.readInt();
+ String name = parcel.readString();
+ PersistableBundle extras = parcel.readPersistableBundle();
+ return new Descriptor(powerComponentId, name, statsArrayLength, uidStatsArrayLength,
+ extras);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Descriptor)) return false;
+ Descriptor that = (Descriptor) o;
+ return powerComponentId == that.powerComponentId
+ && statsArrayLength == that.statsArrayLength
+ && uidStatsArrayLength == that.uidStatsArrayLength
+ && Objects.equals(name, that.name)
+ && extras.size() == that.extras.size() // Unparcel the Parcel if not yet
+ && Bundle.kindofEquals(extras,
+ that.extras); // Since the Parcel is now unparceled, do a deep comparison
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(powerComponentId);
+ }
+
+ @Override
+ public String toString() {
+ if (extras != null) {
+ extras.size(); // Unparcel
+ }
+ return "PowerStats.Descriptor{"
+ + "powerComponentId=" + powerComponentId
+ + ", name='" + name + '\''
+ + ", statsArrayLength=" + statsArrayLength
+ + ", uidStatsArrayLength=" + uidStatsArrayLength
+ + ", extras=" + extras
+ + '}';
+ }
+ }
+
+ /**
+ * A registry for all supported power component types (e.g. CPU, WiFi).
+ */
+ public static class DescriptorRegistry {
+ private final SparseArray<Descriptor> mDescriptors = new SparseArray<>();
+
+ /**
+ * Adds the specified descriptor to the registry. If the registry already
+ * contained a descriptor for the same power component, then the new one replaces
+ * the old one.
+ */
+ public void register(Descriptor descriptor) {
+ mDescriptors.put(descriptor.powerComponentId, descriptor);
+ }
+
+ /**
+ * @param powerComponentId either a BatteryConsumer.PowerComponent or a custom power
+ * component ID
+ */
+ public Descriptor get(int powerComponentId) {
+ return mDescriptors.get(powerComponentId);
+ }
+ }
+
+ public final Descriptor descriptor;
+
+ /**
+ * Duration, in milliseconds, covered by this snapshot.
+ */
+ public long durationMs;
+
+ /**
+ * Device-wide stats.
+ */
+ public long[] stats;
+
+ /**
+ * Per-UID CPU stats.
+ */
+ public final SparseArray<long[]> uidStats = new SparseArray<>();
+
+ public PowerStats(Descriptor descriptor) {
+ this.descriptor = descriptor;
+ stats = new long[descriptor.statsArrayLength];
+ }
+
+ /**
+ * Writes the object into the parcel.
+ */
+ public void writeToParcel(Parcel parcel) {
+ int lengthPos = parcel.dataPosition();
+ parcel.writeInt(0); // Placeholder for length
+
+ int startPos = parcel.dataPosition();
+ parcel.writeInt(descriptor.powerComponentId);
+ parcel.writeLong(durationMs);
+ VARINT_PARCELER.writeLongArray(parcel, stats);
+ parcel.writeInt(uidStats.size());
+ for (int i = 0; i < uidStats.size(); i++) {
+ parcel.writeInt(uidStats.keyAt(i));
+ VARINT_PARCELER.writeLongArray(parcel, uidStats.valueAt(i));
+ }
+
+ int endPos = parcel.dataPosition();
+ parcel.setDataPosition(lengthPos);
+ parcel.writeInt(endPos - startPos);
+ parcel.setDataPosition(endPos);
+ }
+
+ /**
+ * Reads a PowerStats object from the supplied Parcel. If the parcel has an incompatible
+ * format, returns null.
+ */
+ @Nullable
+ public static PowerStats readFromParcel(Parcel parcel, DescriptorRegistry registry) {
+ int length = parcel.readInt();
+ int startPos = parcel.dataPosition();
+ int endPos = startPos + length;
+
+ try {
+ int powerComponentId = parcel.readInt();
+
+ Descriptor descriptor = registry.get(powerComponentId);
+ if (descriptor == null) {
+ Log.e(TAG, "Unsupported PowerStats for power component ID: " + powerComponentId);
+ return null;
+ }
+ PowerStats stats = new PowerStats(descriptor);
+ stats.durationMs = parcel.readLong();
+ stats.stats = new long[descriptor.statsArrayLength];
+ VARINT_PARCELER.readLongArray(parcel, stats.stats);
+ int uidCount = parcel.readInt();
+ for (int i = 0; i < uidCount; i++) {
+ int uid = parcel.readInt();
+ long[] uidStats = new long[descriptor.uidStatsArrayLength];
+ VARINT_PARCELER.readLongArray(parcel, uidStats);
+ stats.uidStats.put(uid, uidStats);
+ }
+ if (parcel.dataPosition() != endPos) {
+ Log.e(TAG, "Corrupted PowerStats parcel. Expected length: " + length
+ + ", actual length: " + (parcel.dataPosition() - startPos));
+ return null;
+ }
+ return stats;
+ } finally {
+ // Unconditionally skip to the end of the written data, even if the actual parcel
+ // format is incompatible
+ parcel.setDataPosition(endPos);
+ }
+ }
+
+ /**
+ * Formats the stats as a string suitable to be included in the Battery History dump.
+ */
+ public String formatForBatteryHistory(String uidPrefix) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("duration=").append(durationMs).append(" ").append(descriptor.name);
+ if (stats.length > 0) {
+ sb.append("=").append(Arrays.toString(stats));
+ }
+ for (int i = 0; i < uidStats.size(); i++) {
+ sb.append(uidPrefix)
+ .append(UserHandle.formatUid(uidStats.keyAt(i)))
+ .append(": ").append(Arrays.toString(uidStats.valueAt(i)));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Prints the contents of the stats snapshot.
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("PowerStats: " + descriptor.name + " (" + descriptor.powerComponentId + ')');
+ pw.increaseIndent();
+ pw.print("duration", durationMs).println();
+ for (int i = 0; i < uidStats.size(); i++) {
+ pw.print("UID ");
+ pw.print(uidStats.keyAt(i));
+ pw.print(": ");
+ pw.print(Arrays.toString(uidStats.valueAt(i)));
+ pw.println();
+ }
+ pw.decreaseIndent();
+ }
+
+ @Override
+ public String toString() {
+ return "PowerStats: " + formatForBatteryHistory(" UID ");
+ }
+}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 5b6b36043684..42be784d8baa 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -149,6 +149,7 @@ public class ConversationLayout extends FrameLayout
private View mAppNameDivider;
private TouchDelegateComposite mTouchDelegate = new TouchDelegateComposite(this);
private ArrayList<MessagingLinearLayout.MessagingChild> mToRecycle = new ArrayList<>();
+ private boolean mPrecomputedTextEnabled = false;
public ConversationLayout(@NonNull Context context) {
super(context);
@@ -389,36 +390,37 @@ public class ConversationLayout extends FrameLayout
*/
@RemotableViewMethod(asyncImpl = "setDataAsync")
public void setData(Bundle extras) {
+ bind(parseMessagingData(extras, /* usePrecomputedText= */ false));
+ }
+
+ @NonNull
+ private MessagingData parseMessagingData(Bundle extras, boolean usePrecomputedText) {
Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
- List<Notification.MessagingStyle.Message> newMessages
- = Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
+ List<Notification.MessagingStyle.Message> newMessages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
- List<Notification.MessagingStyle.Message> newHistoricMessages
- = Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
+ List<Notification.MessagingStyle.Message> newHistoricMessages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
// mUser now set (would be nice to avoid the side effect but WHATEVER)
final Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON, Person.class);
// Append remote input history to newMessages (again, side effect is lame but WHATEVS)
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
- extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, android.app.RemoteInputHistoryItem.class);
+ extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
+ RemoteInputHistoryItem.class);
addRemoteInputHistoryToMessages(newMessages, history);
boolean showSpinner =
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
int unreadCount = extras.getInt(Notification.EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
- // convert MessagingStyle.Message to MessagingMessage, re-using ones from a previous binding
- // if they exist
final List<MessagingMessage> newMessagingMessages =
- createMessages(newMessages, /* isHistoric= */false,
- /* usePrecomputedText= */false);
+ createMessages(newMessages, /* isHistoric= */false, usePrecomputedText);
final List<MessagingMessage> newHistoricMessagingMessages =
- createMessages(newHistoricMessages, /* isHistoric= */true,
- /* usePrecomputedText= */false);
- // bind it, baby
- bindViews(user, showSpinner, unreadCount,
- newMessagingMessages,
- newHistoricMessagingMessages);
+ createMessages(newHistoricMessages, /* isHistoric= */true, usePrecomputedText);
+
+ return new MessagingData(user, showSpinner, unreadCount,
+ newHistoricMessagingMessages, newMessagingMessages);
}
/**
@@ -430,7 +432,33 @@ public class ConversationLayout extends FrameLayout
*/
@NonNull
public Runnable setDataAsync(Bundle extras) {
- return () -> setData(extras);
+ if (!mPrecomputedTextEnabled) {
+ return () -> setData(extras);
+ }
+
+ final MessagingData messagingData =
+ parseMessagingData(extras, /* usePrecomputedText= */ true);
+
+ return () -> {
+ finalizeInflate(messagingData.getHistoricMessagingMessages());
+ finalizeInflate(messagingData.getNewMessagingMessages());
+
+ bind(messagingData);
+ };
+ }
+
+ /**
+ * enable/disable precomputed text usage
+ * @hide
+ */
+ public void setPrecomputedTextEnabled(boolean precomputedTextEnabled) {
+ mPrecomputedTextEnabled = precomputedTextEnabled;
+ }
+
+ private void finalizeInflate(List<MessagingMessage> historicMessagingMessages) {
+ for (MessagingMessage messagingMessage : historicMessagingMessages) {
+ messagingMessage.finalizeInflate();
+ }
}
@Override
@@ -460,17 +488,12 @@ public class ConversationLayout extends FrameLayout
}
}
+ private void bind(MessagingData messagingData) {
+ setUser(messagingData.getUser());
+ setUnreadCount(messagingData.getUnreadCount());
- private void bindViews(Person user,
- boolean showSpinner, int unreadCount, List<MessagingMessage> newMessagingMessages,
- List<MessagingMessage> newHistoricMessagingMessages) {
- setUser(user);
- setUnreadCount(unreadCount);
- bind(showSpinner, newMessagingMessages, newHistoricMessagingMessages);
- }
-
- private void bind(boolean showSpinner, List<MessagingMessage> messages,
- List<MessagingMessage> historicMessages) {
+ List<MessagingMessage> messages = messagingData.getNewMessagingMessages();
+ List<MessagingMessage> historicMessages = messagingData.getHistoricMessagingMessages();
// Copy our groups, before they get clobbered
ArrayList<MessagingGroup> oldGroups = new ArrayList<>(mGroups);
@@ -483,7 +506,7 @@ public class ConversationLayout extends FrameLayout
// Let's now create the views and reorder them accordingly
// side-effect: updates mGroups, mAddedGroups
- createGroupViews(groups, senders, showSpinner);
+ createGroupViews(groups, senders, messagingData.getShowSpinner());
// Let's first check which groups were removed altogether and remove them in one animation
removeGroups(oldGroups);
@@ -585,7 +608,7 @@ public class ConversationLayout extends FrameLayout
// 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);
+ MessagingGroup messagingGroup = mGroups.get(mGroups.size() - 1);
MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage();
if (isolatedMessage != null) {
newMessage = isolatedMessage.getView();
@@ -1042,7 +1065,7 @@ public class ConversationLayout extends FrameLayout
}
if (visibleChildren > 0 && group.getVisibility() == GONE) {
group.setVisibility(VISIBLE);
- } else if (visibleChildren == 0 && group.getVisibility() != GONE) {
+ } else if (visibleChildren == 0 && group.getVisibility() != GONE) {
group.setVisibility(GONE);
}
}
@@ -1259,7 +1282,7 @@ public class ConversationLayout extends FrameLayout
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
- for (TouchDelegate delegate: mDelegates) {
+ for (TouchDelegate delegate : mDelegates) {
event.setLocation(x, y);
if (delegate.onTouchEvent(event)) {
return true;
diff --git a/core/java/com/android/internal/widget/MessagingData.java b/core/java/com/android/internal/widget/MessagingData.java
new file mode 100644
index 000000000000..85b02018e7c7
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingData.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.app.Person;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+final class MessagingData {
+ private final Person mUser;
+ private final boolean mShowSpinner;
+ private final List<MessagingMessage> mHistoricMessagingMessages;
+ private final List<MessagingMessage> mNewMessagingMessages;
+ private final int mUnreadCount;
+
+ MessagingData(Person user, boolean showSpinner,
+ List<MessagingMessage> historicMessagingMessages,
+ List<MessagingMessage> newMessagingMessages) {
+ this(user, showSpinner, /* unreadCount= */0,
+ historicMessagingMessages, newMessagingMessages);
+ }
+
+ MessagingData(Person user, boolean showSpinner,
+ int unreadCount,
+ List<MessagingMessage> historicMessagingMessages,
+ List<MessagingMessage> newMessagingMessages) {
+ mUser = user;
+ mShowSpinner = showSpinner;
+ mUnreadCount = unreadCount;
+ mHistoricMessagingMessages = historicMessagingMessages;
+ mNewMessagingMessages = newMessagingMessages;
+ }
+
+ public Person getUser() {
+ return mUser;
+ }
+
+ public boolean getShowSpinner() {
+ return mShowSpinner;
+ }
+
+ public List<MessagingMessage> getHistoricMessagingMessages() {
+ return mHistoricMessagingMessages;
+ }
+
+ public List<MessagingMessage> getNewMessagingMessages() {
+ return mNewMessagingMessages;
+ }
+
+ public int getUnreadCount() {
+ return mUnreadCount;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 83557cd8a719..b6d7503119fe 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -87,7 +87,7 @@ public class MessagingLayout extends FrameLayout
private ImageResolver mImageResolver;
private CharSequence mConversationTitle;
private ArrayList<MessagingLinearLayout.MessagingChild> mToRecycle = new ArrayList<>();
-
+ private boolean mPrecomputedTextEnabled = false;
public MessagingLayout(@NonNull Context context) {
super(context);
}
@@ -162,15 +162,23 @@ public class MessagingLayout extends FrameLayout
*/
@RemotableViewMethod(asyncImpl = "setDataAsync")
public void setData(Bundle extras) {
+ bind(parseMessagingData(extras, /* usePrecomputedText= */false));
+ }
+
+ @NonNull
+ private MessagingData parseMessagingData(Bundle extras, boolean usePrecomputedText) {
Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
- List<Notification.MessagingStyle.Message> newMessages
- = Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
+ List<Notification.MessagingStyle.Message> newMessages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
- List<Notification.MessagingStyle.Message> newHistoricMessages
- = Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
- setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON, android.app.Person.class));
- RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
- extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, android.app.RemoteInputHistoryItem.class);
+ List<Notification.MessagingStyle.Message> newHistoricMessages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
+ setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON,
+ Person.class));
+ RemoteInputHistoryItem[] history =
+ (RemoteInputHistoryItem[]) extras.getParcelableArray(
+ Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
+ RemoteInputHistoryItem.class);
addRemoteInputHistoryToMessages(newMessages, history);
final Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON, Person.class);
@@ -178,10 +186,12 @@ public class MessagingLayout extends FrameLayout
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
final List<MessagingMessage> historicMessagingMessages = createMessages(newHistoricMessages,
- /* isHistoric= */true, /* usePrecomputedText= */ false);
+ /* isHistoric= */true, usePrecomputedText);
final List<MessagingMessage> newMessagingMessages =
- createMessages(newMessages, /* isHistoric= */false, /* usePrecomputedText= */false);
- bindViews(user, showSpinner, historicMessagingMessages, newMessagingMessages);
+ createMessages(newMessages, /* isHistoric */false, usePrecomputedText);
+
+ return new MessagingData(user, showSpinner,
+ historicMessagingMessages, newMessagingMessages);
}
/**
@@ -193,7 +203,32 @@ public class MessagingLayout extends FrameLayout
*/
@NonNull
public Runnable setDataAsync(Bundle extras) {
- return () -> setData(extras);
+ if (!mPrecomputedTextEnabled) {
+ return () -> setData(extras);
+ }
+
+ final MessagingData messagingData =
+ parseMessagingData(extras, /* usePrecomputedText= */true);
+
+ return () -> {
+ finalizeInflate(messagingData.getHistoricMessagingMessages());
+ finalizeInflate(messagingData.getNewMessagingMessages());
+ bind(messagingData);
+ };
+ }
+
+ /**
+ * enable/disable precomputed text usage
+ * @hide
+ */
+ public void setPrecomputedTextEnabled(boolean precomputedTextEnabled) {
+ mPrecomputedTextEnabled = precomputedTextEnabled;
+ }
+
+ private void finalizeInflate(List<MessagingMessage> historicMessagingMessages) {
+ for (MessagingMessage messagingMessage: historicMessagingMessages) {
+ messagingMessage.finalizeInflate();
+ }
}
@Override
@@ -218,17 +253,13 @@ public class MessagingLayout extends FrameLayout
}
}
- private void bindViews(Person user, boolean showSpinner,
- List<MessagingMessage> historicMessagingMessages,
- List<MessagingMessage> newMessagingMessages) {
- setUser(user);
- bind(showSpinner, historicMessagingMessages, newMessagingMessages);
- }
+ private void bind(MessagingData messagingData) {
+ setUser(messagingData.getUser());
- private void bind(boolean showSpinner, List<MessagingMessage> historicMessages,
- List<MessagingMessage> messages) {
+ List<MessagingMessage> historicMessages = messagingData.getHistoricMessagingMessages();
+ List<MessagingMessage> messages = messagingData.getNewMessagingMessages();
ArrayList<MessagingGroup> oldGroups = new ArrayList<>(mGroups);
- addMessagesToGroups(historicMessages, messages, showSpinner);
+ addMessagesToGroups(historicMessages, messages, messagingData.getShowSpinner());
// Let's first check which groups were removed altogether and remove them in one animation
removeGroups(oldGroups);
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index de429a07d0f6..760037f63195 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -52,7 +52,7 @@ static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz
env->ReleaseStringUTFChars(file, filePath);
- const char* packageNameStr = obb->getPackageName().string();
+ const char* packageNameStr = obb->getPackageName().c_str();
jstring packageName = env->NewStringUTF(packageNameStr);
if (packageName == NULL) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 9c6a534c3bbb..deb138fda867 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -150,7 +150,7 @@ static jstring getJavaInternedString(JNIEnv *env, const String8 &string) {
return gStringOffsets.emptyString;
}
- ScopedLocalRef<jstring> javaString(env, env->NewStringUTF(string.string()));
+ ScopedLocalRef<jstring> javaString(env, env->NewStringUTF(string.c_str()));
jstring internedString = (jstring)
env->CallObjectMethod(javaString.get(), gStringOffsets.intern);
return internedString;
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index eb5f2977e221..ea3c70f5e60b 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -35,6 +35,7 @@
#include "android_util_Binder.h"
#include "core_jni_helpers.h"
#include "jni.h"
+#include "jni_common.h"
namespace android {
@@ -57,10 +58,7 @@ static struct {
jfieldID layoutParamsFlags;
jfieldID layoutParamsType;
jfieldID dispatchingTimeoutMillis;
- jfieldID frameLeft;
- jfieldID frameTop;
- jfieldID frameRight;
- jfieldID frameBottom;
+ jfieldID frame;
jfieldID surfaceInset;
jfieldID scaleFactor;
jfieldID touchableRegion;
@@ -128,14 +126,11 @@ bool NativeInputWindowHandle::updateInfo() {
mInfo.dispatchingTimeout = std::chrono::milliseconds(
env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
- mInfo.frameLeft = env->GetIntField(obj,
- gInputWindowHandleClassInfo.frameLeft);
- mInfo.frameTop = env->GetIntField(obj,
- gInputWindowHandleClassInfo.frameTop);
- mInfo.frameRight = env->GetIntField(obj,
- gInputWindowHandleClassInfo.frameRight);
- mInfo.frameBottom = env->GetIntField(obj,
- gInputWindowHandleClassInfo.frameBottom);
+
+ ScopedLocalRef<jobject> frameObj(env,
+ env->GetObjectField(obj, gInputWindowHandleClassInfo.frame));
+ mInfo.frame = JNICommon::rectFromObj(env, frameObj.get());
+
mInfo.surfaceInset = env->GetIntField(obj,
gInputWindowHandleClassInfo.surfaceInset);
mInfo.globalScaleFactor = env->GetFloatField(obj,
@@ -283,13 +278,9 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn
std::chrono::duration_cast<std::chrono::milliseconds>(
windowInfo.dispatchingTimeout)
.count());
- env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameLeft,
- windowInfo.frameLeft);
- env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameTop, windowInfo.frameTop);
- env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameRight,
- windowInfo.frameRight);
- env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameBottom,
- windowInfo.frameBottom);
+ ScopedLocalRef<jobject> rectObj(env, JNICommon::objFromRect(env, windowInfo.frame));
+ env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.frame, rectObj.get());
+
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.surfaceInset,
windowInfo.surfaceInset);
env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.scaleFactor,
@@ -400,17 +391,7 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutMillis, clazz,
"dispatchingTimeoutMillis", "J");
- GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
- "frameLeft", "I");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.frameTop, clazz,
- "frameTop", "I");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.frameRight, clazz,
- "frameRight", "I");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz,
- "frameBottom", "I");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frame, clazz, "frame", "Landroid/graphics/Rect;");
GET_FIELD_ID(gInputWindowHandleClassInfo.surfaceInset, clazz,
"surfaceInset", "I");
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 979c9e3ea7a3..f04b901ff0df 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -295,7 +295,7 @@ static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
if (alloc.length() <= 0) {
return nullptr;
}
- return env->NewStringUTF(alloc.string());
+ return env->NewStringUTF(alloc.c_str());
}
static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
@@ -456,7 +456,7 @@ static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring
}
for (size_t i = 0; i < file_count; i++) {
- jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
+ jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).c_str());
// Check for errors creating the strings (if malformed or no memory).
if (env->ExceptionCheck()) {
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index 76f5c107c970..69202111f74c 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -65,6 +65,16 @@ static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativeP
counter->updateValue(*vector, timestamp);
}
+static void native_incrementValues(jlong nativePtr, jlong longArrayContainerNativePtr,
+ jlong timestamp) {
+ battery::LongArrayMultiStateCounter *counter =
+ reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+ std::vector<uint64_t> *vector =
+ reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
+
+ counter->incrementValue(*vector, timestamp);
+}
+
static void native_addCounts(jlong nativePtr, jlong longArrayContainerNativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
@@ -202,6 +212,8 @@ static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
// @CriticalNative
{"native_updateValues", "(JJJ)V", (void *)native_updateValues},
// @CriticalNative
+ {"native_incrementValues", "(JJJ)V", (void *)native_incrementValues},
+ // @CriticalNative
{"native_addCounts", "(JJ)V", (void *)native_addCounts},
// @CriticalNative
{"native_reset", "(J)V", (void *)native_reset},
diff --git a/core/jni/jni_common.cpp b/core/jni/jni_common.cpp
index 8d376cf2c7f9..b81c9b6eed95 100644
--- a/core/jni/jni_common.cpp
+++ b/core/jni/jni_common.cpp
@@ -26,6 +26,8 @@
namespace android {
static struct {
+ jclass clazz;
+ jmethodID ctor;
jfieldID bottom;
jfieldID left;
jfieldID right;
@@ -40,8 +42,15 @@ Rect JNICommon::rectFromObj(JNIEnv* env, jobject rectObj) {
return Rect(left, top, right, bottom);
}
+jobject JNICommon::objFromRect(JNIEnv* env, Rect rect) {
+ return env->NewObject(gRectClassInfo.clazz, gRectClassInfo.ctor, rect.left, rect.top,
+ rect.right, rect.bottom);
+}
+
int register_jni_common(JNIEnv* env) {
jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
+ gRectClassInfo.clazz = MakeGlobalRefOrDie(env, rectClazz);
+ gRectClassInfo.ctor = GetMethodIDOrDie(env, rectClazz, "<init>", "(IIII)V");
gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
gRectClassInfo.left = GetFieldIDOrDie(env, rectClazz, "left", "I");
gRectClassInfo.right = GetFieldIDOrDie(env, rectClazz, "right", "I");
diff --git a/core/jni/jni_common.h b/core/jni/jni_common.h
index a2bf6fb3f5e0..d670a7d6bd59 100644
--- a/core/jni/jni_common.h
+++ b/core/jni/jni_common.h
@@ -22,5 +22,6 @@ class Rect;
class JNICommon {
public:
static Rect rectFromObj(JNIEnv* env, jobject rectObj);
+ static jobject objFromRect(JNIEnv* env, Rect rect);
};
} // namespace android \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f55501ab1a8f..ffd640fe36ea 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2267,6 +2267,14 @@
<permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS"
android:protectionLevel="signature" />
+ <!-- Allows system apps to call methods to register itself as a mDNS offload engine.
+ <p>Not for use by third-party or privileged applications.
+ @SystemApi
+ @hide This should only be used by system apps.
+ -->
+ <permission android:name="android.permission.REGISTER_NSD_OFFLOAD_ENGINE"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2f0b390d92c2..281053b6ce7b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -542,6 +542,9 @@
<bool name="config_goToSleepOnButtonPressTheaterMode">true</bool>
<!-- If this is true, long press on power button will be available from the non-interactive state -->
<bool name="config_supportLongPressPowerWhenNonInteractive">false</bool>
+ <!-- If this is true, short press on power button will be available whenever the default display
+ is on even if the device is non-interactive (dreaming). -->
+ <bool name="config_supportShortPressPowerWhenDefaultDisplayOn">false</bool>
<!-- If this is true, then keep dreaming when unplugging.
This config was formerly known as config_keepDreamingWhenUndocking.
@@ -1207,13 +1210,16 @@
<integer name="config_triplePressOnStemPrimaryBehavior">0</integer>
<!-- Control the behavior when the user short presses the stem primary button.
- Stem primary button is only used on watch form factor. If a device is not
- a watch, setting this config is no-op.
- 0 - Nothing
- 1 - Go to launch all apps
+ Stem primary button is only used on watch form factor. If a device is not
+ a watch, setting this config is no-op.
+ 0 - Nothing
+ 1 - Go to launch all apps
+ 2 - Launch target activity defined by config_primaryShortPressTargetActivity if available
-->
<integer name="config_shortPressOnStemPrimaryBehavior">0</integer>
+ <!-- Activity name for the default target activity to be launched. [DO NOT TRANSLATE] -->
+ <string name="config_primaryShortPressTargetActivity" translatable="false"></string>
<!-- Control the behavior of the search key.
0 - Launch default search activity
@@ -5353,6 +5359,7 @@
<item>1,1,1.0,0,1</item>
<item>1,1,1.0,.4,1</item>
<item>1,1,1.0,.15,15</item>
+ <item>0,0,0.7,0,1</item>
</string-array>
<!-- The integer index of the selected option in config_udfps_touch_detection_options -->
@@ -6621,11 +6628,6 @@
<!-- Whether to show weather on the lock screen by default. -->
<bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
- <!-- Whether to reset Battery Stats on unplug when the battery level is high. -->
- <bool name="config_batteryStatsResetOnUnplugHighBatteryLevel">true</bool>
- <!-- Whether to reset Battery Stats on unplug if the battery was significantly charged -->
- <bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool>
-
<!-- Whether we should persist the brightness value in nits for the default display even if
the underlying display device changes. -->
<bool name="config_persistBrightnessNitsForDefaultDisplay">false</bool>
diff --git a/core/res/res/values/config_battery_stats.xml b/core/res/res/values/config_battery_stats.xml
new file mode 100644
index 000000000000..8fb48bcb8947
--- /dev/null
+++ b/core/res/res/values/config_battery_stats.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. Do not translate.
+
+ NOTE: The naming convention is "config_camelCaseValue". -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Whether to reset Battery Stats on unplug when the battery level is high. -->
+ <bool name="config_batteryStatsResetOnUnplugHighBatteryLevel">true</bool>
+ <!-- Whether to reset Battery Stats on unplug if the battery was significantly charged -->
+ <bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool>
+
+ <!-- CPU power stats collection throttle period in milliseconds. Since power stats collection
+ is a relatively expensive operation, this throttle period may need to be adjusted for low-power
+ devices-->
+ <integer name="config_defaultPowerStatsThrottlePeriodCpu">60000</integer>
+</resources>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index bda194add759..6bb87f3c4e99 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -73,7 +73,7 @@
CarrierConfigManager#KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_STRING_ARRAY.
If 0, the device always switch to the higher score SIM.
If < 0, the network type and signal strength based auto switch is disabled. -->
- <integer name="auto_data_switch_score_tolerance">3000</integer>
+ <integer name="auto_data_switch_score_tolerance">-1</integer>
<java-symbol type="integer" name="auto_data_switch_score_tolerance" />
<!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0dd6c749b5a9..207927af95f6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5561,7 +5561,7 @@
<!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
in an autofill service, and the service knows what the activity represents, and it represents 3 types of
data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
- <string name="autofill_update_title_with_3types">Update these items in <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>: <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> ?</string>
+ <string name="autofill_update_title_with_3types">Update these items in <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>: <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g>?</string>
<!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
<string name="autofill_save_yes">Save</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f1a78a6a1e7d..aa0cbfa92043 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -466,6 +466,7 @@
<java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
<java-symbol type="integer" name="config_longPressOnStemPrimaryBehavior" />
<java-symbol type="integer" name="config_shortPressOnStemPrimaryBehavior" />
+ <java-symbol type="string" name="config_primaryShortPressTargetActivity" />
<java-symbol type="integer" name="config_doublePressOnStemPrimaryBehavior" />
<java-symbol type="integer" name="config_triplePressOnStemPrimaryBehavior" />
<java-symbol type="string" name="config_doublePressOnPowerTargetActivity" />
@@ -1968,6 +1969,7 @@
<java-symbol type="integer" name="config_keyguardDrawnTimeout" />
<java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" />
<java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" />
+ <java-symbol type="bool" name="config_supportShortPressPowerWhenDefaultDisplayOn" />
<java-symbol type="bool" name="config_wimaxEnabled" />
<java-symbol type="bool" name="show_ongoing_ime_switcher" />
<java-symbol type="color" name="config_defaultNotificationColor" />
@@ -5088,6 +5090,7 @@
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />
+ <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodCpu" />
<java-symbol name="materialColorOnSecondaryFixedVariant" type="attr"/>
<java-symbol name="materialColorOnTertiaryFixedVariant" type="attr"/>
diff --git a/core/tests/coretests/res/values-id/strings.xml b/core/tests/coretests/res/values-id/strings.xml
new file mode 100644
index 000000000000..6d71c90866cc
--- /dev/null
+++ b/core/tests/coretests/res/values-id/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Used in ResourcesLocaleTest. -->
+ <string name="locale_test_res_1">Pengujian ID</string>
+</resources>
diff --git a/core/tests/coretests/res/values-in/strings.xml b/core/tests/coretests/res/values-in/strings.xml
new file mode 100644
index 000000000000..63846603ed60
--- /dev/null
+++ b/core/tests/coretests/res/values-in/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Used in ResourcesLocaleTest. -->
+ <string name="locale_test_res_2">Pengujian IN</string>
+</resources>
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index e51eab60a998..09e1c690f4e2 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -131,6 +131,13 @@
<string name="textview_hebrew_text">&#x05DD;&#x05DE;ab?!</string>
+ <!-- Used in ResourcesLocaleTest. Also defined in values-id. "id" is the new ISO code for Indonesian. -->
+ <string name="locale_test_res_1">Testing ID</string>
+ <!-- Used in ResourcesLocaleTest. Also defined in values-in. "in" is the deprecated ISO code for Indonesian. -->
+ <string name="locale_test_res_2">Testing IN</string>
+ <!-- Used in ResourcesLocaleTest. -->
+ <string name="locale_test_res_3">Testing EN</string>
+
<!-- SizeAdaptiveLayout -->
<string name="first">Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.</string>
<string name="actor">Abe Lincoln</string>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 91c4ddebd1a1..a9234791247e 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -67,6 +67,7 @@ import android.view.View;
import android.window.WindowContextInfo;
import android.window.WindowTokenClientController;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
@@ -629,6 +630,7 @@ public class ActivityThreadTest {
});
}
+ @FlakyTest(bugId = 295234586)
@Test
public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
@@ -643,7 +645,8 @@ public class ActivityThreadTest {
new Configuration(oldAppResources.getConfiguration());
final DisplayMetrics oldApplicationMetrics = new DisplayMetrics();
oldApplicationMetrics.setTo(oldAppResources.getDisplayMetrics());
- assertEquals("Process config must match the top activity config by default",
+ assertEquals("Process config must match the top activity config by default"
+ + ", activity=" + oldActivityConfig + ", app=" + oldAppConfig,
0, oldActivityConfig.diffPublicOnly(oldAppConfig));
assertEquals("Process config must match the top activity config by default",
oldActivityMetrics, oldApplicationMetrics);
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index 10452fd64430..bc6990181c6f 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -110,6 +110,7 @@ public class BroadcastTest extends ActivityTestsBase {
public Intent makeBroadcastIntent(String action) {
Intent intent = new Intent(action, null);
intent.putExtra("caller", mCallTarget);
+ intent.setPackage(getContext().getPackageName());
return intent;
}
@@ -179,7 +180,8 @@ public class BroadcastTest extends ActivityTestsBase {
public void registerMyReceiver(IntentFilter filter, String permission) {
mReceiverRegistered = true;
//System.out.println("Registering: " + mReceiver);
- getContext().registerReceiver(mReceiver, filter, permission, null);
+ getContext().registerReceiver(mReceiver, filter, permission, null,
+ Context.RECEIVER_EXPORTED);
}
public void unregisterMyReceiver() {
@@ -255,7 +257,7 @@ public class BroadcastTest extends ActivityTestsBase {
}
@FlakyTest
- public void testMulti() throws Exception {
+ public void ignore_testMulti() throws Exception {
runLaunchpad(LaunchpadActivity.BROADCAST_MULTI);
}
@@ -278,8 +280,11 @@ public class BroadcastTest extends ActivityTestsBase {
Bundle map = new Bundle();
map.putString("foo", "you");
map.putString("remove", "me");
+ final Intent intent = new Intent(
+ "com.android.frameworks.coretests.activity.BROADCAST_RESULT")
+ .setPackage(getContext().getPackageName());
getContext().sendOrderedBroadcast(
- new Intent("com.android.frameworks.coretests.activity.BROADCAST_RESULT"),
+ intent,
null, broadcastReceiver, null, 1, "foo", map);
while (!broadcastReceiver.mHaveResult) {
try {
@@ -313,7 +318,7 @@ public class BroadcastTest extends ActivityTestsBase {
addIntermediate("finished-broadcast");
IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
- Intent sticky = getContext().registerReceiver(null, filter);
+ Intent sticky = getContext().registerReceiver(null, filter, Context.RECEIVER_EXPORTED);
assertNotNull("Sticky not found", sticky);
assertEquals(LaunchpadActivity.DATA_1, sticky.getStringExtra("test"));
}
@@ -329,7 +334,7 @@ public class BroadcastTest extends ActivityTestsBase {
addIntermediate("finished-unbroadcast");
IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
- Intent sticky = getContext().registerReceiver(null, filter);
+ Intent sticky = getContext().registerReceiver(null, filter, Context.RECEIVER_EXPORTED);
assertNull("Sticky not found", sticky);
}
@@ -343,7 +348,7 @@ public class BroadcastTest extends ActivityTestsBase {
addIntermediate("finished-broadcast");
IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
- Intent sticky = getContext().registerReceiver(null, filter);
+ Intent sticky = getContext().registerReceiver(null, filter, Context.RECEIVER_EXPORTED);
assertNotNull("Sticky not found", sticky);
assertEquals(LaunchpadActivity.DATA_2, sticky.getStringExtra("test"));
}
@@ -371,7 +376,7 @@ public class BroadcastTest extends ActivityTestsBase {
runLaunchpad(LaunchpadActivity.BROADCAST_STICKY2);
}
- public void testRegisteredReceivePermissionGranted() throws Exception {
+ public void ignore_testRegisteredReceivePermissionGranted() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_REG});
registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED);
addIntermediate("after-register");
@@ -396,7 +401,7 @@ public class BroadcastTest extends ActivityTestsBase {
waitForResultOrThrow(BROADCAST_TIMEOUT);
}
- public void testRegisteredBroadcastPermissionGranted() throws Exception {
+ public void ignore_testRegisteredBroadcastPermissionGranted() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_REG});
registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
addIntermediate("after-register");
@@ -430,7 +435,7 @@ public class BroadcastTest extends ActivityTestsBase {
waitForResultOrThrow(BROADCAST_TIMEOUT);
}
- public void testLocalReceivePermissionDenied() throws Exception {
+ public void ignore_testLocalReceivePermissionDenied() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_RESULTS});
BroadcastReceiver finish = new BroadcastReceiver() {
@@ -446,7 +451,7 @@ public class BroadcastTest extends ActivityTestsBase {
waitForResultOrThrow(BROADCAST_TIMEOUT);
}
- public void testLocalBroadcastPermissionGranted() throws Exception {
+ public void ignore_testLocalBroadcastPermissionGranted() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_LOCAL});
getContext().sendBroadcast(
makeBroadcastIntent(BROADCAST_LOCAL),
@@ -476,7 +481,7 @@ public class BroadcastTest extends ActivityTestsBase {
waitForResultOrThrow(BROADCAST_TIMEOUT);
}
- public void testRemoteReceivePermissionDenied() throws Exception {
+ public void ignore_testRemoteReceivePermissionDenied() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_RESULTS});
BroadcastReceiver finish = new BroadcastReceiver() {
@@ -492,7 +497,7 @@ public class BroadcastTest extends ActivityTestsBase {
waitForResultOrThrow(BROADCAST_TIMEOUT);
}
- public void testRemoteBroadcastPermissionGranted() throws Exception {
+ public void ignore_testRemoteBroadcastPermissionGranted() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_REMOTE});
getContext().sendBroadcast(
makeBroadcastIntent(BROADCAST_REMOTE),
@@ -516,7 +521,7 @@ public class BroadcastTest extends ActivityTestsBase {
waitForResultOrThrow(BROADCAST_TIMEOUT);
}
- public void testReceiverCanNotRegister() throws Exception {
+ public void ignore_testReceiverCanNotRegister() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_LOCAL});
getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_REGISTER));
waitForResultOrThrow(BROADCAST_TIMEOUT);
diff --git a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
index 1b52f8050f33..a0645ce11249 100644
--- a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
+++ b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
@@ -27,7 +27,7 @@ import androidx.test.filters.LargeTest;
@LargeTest
public class IntentSenderTest extends BroadcastTest {
- public void testRegisteredReceivePermissionGranted() throws Exception {
+ public void ignore_testRegisteredReceivePermissionGranted() throws Exception {
setExpectedReceivers(new String[]{RECEIVER_REG});
registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED);
addIntermediate("after-register");
@@ -71,7 +71,7 @@ public class IntentSenderTest extends BroadcastTest {
is.cancel();
}
- public void testLocalReceivePermissionDenied() throws Exception {
+ public void ignore_testLocalReceivePermissionDenied() throws Exception {
final Intent intent = makeBroadcastIntent(BROADCAST_LOCAL_DENIED)
.setPackage(getContext().getPackageName());
diff --git a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
index 766245600d13..fda249f3c6ae 100644
--- a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
+++ b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
@@ -438,6 +438,7 @@ public class LaunchpadActivity extends Activity {
private Intent makeBroadcastIntent(String action) {
Intent intent = new Intent(action, null);
intent.putExtra("caller", mCallTarget);
+ intent.setPackage(getPackageName());
return intent;
}
@@ -466,7 +467,7 @@ public class LaunchpadActivity extends Activity {
private void registerMyReceiver(IntentFilter filter) {
mReceiverRegistered = true;
//System.out.println("Registering: " + mReceiver);
- registerReceiver(mReceiver, filter);
+ registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED);
}
private void unregisterMyReceiver() {
diff --git a/core/tests/coretests/src/android/app/activity/LocalDeniedReceiver.java b/core/tests/coretests/src/android/app/activity/LocalDeniedReceiver.java
index 2120a1db463c..3271b8fa124a 100644
--- a/core/tests/coretests/src/android/app/activity/LocalDeniedReceiver.java
+++ b/core/tests/coretests/src/android/app/activity/LocalDeniedReceiver.java
@@ -19,11 +19,11 @@ package android.app.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.RemoteException;
-class LocalDeniedReceiver extends BroadcastReceiver {
+public class LocalDeniedReceiver extends BroadcastReceiver {
public LocalDeniedReceiver() {
}
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
index 25c3db5c6910..26e4349243a5 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.content.Context;
import android.os.FileUtils;
import android.os.LocaleList;
import android.platform.test.annotations.Presubmit;
@@ -97,4 +98,24 @@ public class ResourcesLocaleTest extends AndroidTestCase {
assertEquals(Locale.forLanguageTag("pl-PL"),
resources.getConfiguration().getLocales().get(0));
}
+
+ @SmallTest
+ public void testDeprecatedISOLanguageCode() {
+ assertResGetString(Locale.US, R.string.locale_test_res_1, "Testing ID");
+ assertResGetString(Locale.forLanguageTag("id"), R.string.locale_test_res_2, "Pengujian IN");
+ assertResGetString(Locale.forLanguageTag("id"), R.string.locale_test_res_3, "Testing EN");
+ assertResGetString(new Locale("id"), R.string.locale_test_res_2, "Pengujian IN");
+ assertResGetString(new Locale("id"), R.string.locale_test_res_3, "Testing EN");
+ // The new ISO code "id" isn't supported yet, and thus the values-id are ignored.
+ assertResGetString(new Locale("id"), R.string.locale_test_res_1, "Testing ID");
+ assertResGetString(Locale.forLanguageTag("id"), R.string.locale_test_res_1, "Testing ID");
+ }
+
+ private void assertResGetString(Locale locale, int resId, String expectedString) {
+ LocaleList locales = new LocaleList(locale);
+ final Configuration config = new Configuration();
+ config.setLocales(locales);
+ Context newContext = getContext().createConfigurationContext(config);
+ assertEquals(expectedString, newContext.getResources().getString(resId));
+ }
}
diff --git a/core/tests/coretests/src/android/service/TEST_MAPPING b/core/tests/coretests/src/android/service/TEST_MAPPING
new file mode 100644
index 000000000000..fbf8a92e031d
--- /dev/null
+++ b/core/tests/coretests/src/android/service/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "postsubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {"include-filter": "android.service.controls"},
+ {"include-filter": "android.service.controls.actions"},
+ {"include-filter": "android.service.controls.templates"},
+ {"include-filter": "android.service.euicc"},
+ {"include-filter": "android.service.notification"},
+ {"include-filter": "android.service.quicksettings"},
+ {"include-filter": "android.service.settings.suggestions"},
+ {"include-filter": "android.service.timezone"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ }
+ ]
+}
diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
index 0af8c728aba3..6792d0b91084 100644
--- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
+++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
@@ -239,7 +239,7 @@ public class EuiccProfileInfoTest {
assertNotEquals(p.hashCode(), t.hashCode());
}
- @Test(expected = IllegalStateException.class)
+ @Test(expected = IllegalArgumentException.class)
public void testBuilderBuild_IllegalIccid() {
new EuiccProfileInfo.Builder("abc").build();
}
diff --git a/core/tests/coretests/src/android/service/euicc/OWNERS b/core/tests/coretests/src/android/service/euicc/OWNERS
new file mode 100644
index 000000000000..41fc56b45dde
--- /dev/null
+++ b/core/tests/coretests/src/android/service/euicc/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/telephony/java/android/service/euicc/OWNERS
diff --git a/core/tests/coretests/src/android/service/quicksettings/TileTest.java b/core/tests/coretests/src/android/service/quicksettings/TileTest.java
new file mode 100644
index 000000000000..ca6c3b443aa6
--- /dev/null
+++ b/core/tests/coretests/src/android/service/quicksettings/TileTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.quicksettings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TileTest {
+
+ private static final String DEFAULT_LABEL = "DEFAULT_LABEL";
+ private static final String CUSTOM_APP_LABEL = "CUSTOM_LABEL";
+
+ @Test
+ public void testGetLabel_labelSet_usesCustomLabel() {
+ Tile tile = new Tile();
+ tile.setDefaultLabel(DEFAULT_LABEL);
+ tile.setLabel(CUSTOM_APP_LABEL);
+
+ assertThat(tile.getLabel()).isEqualTo(CUSTOM_APP_LABEL);
+ }
+
+ @Test
+ public void testGetLabel_labelNotSet_usesDefaultLabel() {
+ Tile tile = new Tile();
+ tile.setDefaultLabel(DEFAULT_LABEL);
+
+ assertThat(tile.getLabel()).isEqualTo(DEFAULT_LABEL);
+ }
+
+ @Test
+ public void testGetCustomLabel_labelSet() {
+ Tile tile = new Tile();
+ tile.setDefaultLabel(DEFAULT_LABEL);
+ tile.setLabel(CUSTOM_APP_LABEL);
+
+ assertThat(tile.getCustomLabel()).isEqualTo(CUSTOM_APP_LABEL);
+ }
+
+ @Test
+ public void testGetCustomLabel_labelNotSet() {
+ Tile tile = new Tile();
+ tile.setDefaultLabel(DEFAULT_LABEL);
+
+ assertThat(tile.getCustomLabel()).isNull();
+ }
+}
diff --git a/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java b/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
new file mode 100644
index 000000000000..a8b40325a713
--- /dev/null
+++ b/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window.flags;
+
+import static com.android.window.flags.Flags.syncWindowConfigUpdateFlag;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link com.android.window.flags.Flags}
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:WindowFlagsTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class WindowFlagsTest {
+
+ @Test
+ public void testSyncWindowConfigUpdateFlag() {
+ // No crash when accessing the flag.
+ syncWindowConfigUpdateFlag();
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 38c3aa04ea35..2cbeaa17332c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -35,8 +35,9 @@ import org.junit.runners.Suite;
LongArrayMultiStateCounterTest.class,
LongMultiStateCounterTest.class,
PowerProfileTest.class,
+ PowerStatsTest.class,
EnergyConsumerStatsTest.class
})
public class BatteryStatsTests {
-} \ No newline at end of file
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
new file mode 100644
index 000000000000..29da2319adc2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.Parcel;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PowerStatsTest {
+
+ private PowerStats.DescriptorRegistry mRegistry;
+ private PowerStats.Descriptor mDescriptor;
+
+ @Before
+ public void setup() {
+ mRegistry = new PowerStats.DescriptorRegistry();
+ PersistableBundle extras = new PersistableBundle();
+ extras.putBoolean("hasPowerMonitor", true);
+ mDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU, 3, 2, extras);
+ mRegistry.register(mDescriptor);
+ }
+
+ @Test
+ public void parceling_compatibleParcel() {
+ PowerStats stats = new PowerStats(mDescriptor);
+ stats.durationMs = 1234;
+ stats.stats[0] = 10;
+ stats.stats[1] = 20;
+ stats.stats[2] = 30;
+ stats.uidStats.put(42, new long[]{40, 50});
+ stats.uidStats.put(99, new long[]{60, 70});
+
+ Parcel parcel = Parcel.obtain();
+ mDescriptor.writeSummaryToParcel(parcel);
+ stats.writeToParcel(parcel);
+ parcel.writeString("END");
+
+ Parcel newParcel = marshallAndUnmarshall(parcel);
+
+ PowerStats.Descriptor newDescriptor =
+ PowerStats.Descriptor.readSummaryFromParcel(newParcel);
+ assertThat(newDescriptor.powerComponentId).isEqualTo(BatteryConsumer.POWER_COMPONENT_CPU);
+ assertThat(newDescriptor.name).isEqualTo("cpu");
+ assertThat(newDescriptor.statsArrayLength).isEqualTo(3);
+ assertThat(newDescriptor.uidStatsArrayLength).isEqualTo(2);
+ assertThat(newDescriptor.extras.getBoolean("hasPowerMonitor")).isTrue();
+
+ mRegistry.register(newDescriptor);
+
+ PowerStats newStats = PowerStats.readFromParcel(newParcel, mRegistry);
+ assertThat(newStats.durationMs).isEqualTo(1234);
+ assertThat(newStats.stats).isEqualTo(new long[]{10, 20, 30});
+ assertThat(newStats.uidStats.size()).isEqualTo(2);
+ assertThat(newStats.uidStats.get(42)).isEqualTo(new long[]{40, 50});
+ assertThat(newStats.uidStats.get(99)).isEqualTo(new long[]{60, 70});
+
+ String end = newParcel.readString();
+ assertThat(end).isEqualTo("END");
+ }
+
+ @Test
+ public void parceling_unrecognizedPowerComponent() {
+ PowerStats stats = new PowerStats(
+ new PowerStats.Descriptor(777, "luck", 3, 2, new PersistableBundle()));
+ stats.durationMs = 1234;
+
+ Parcel parcel = Parcel.obtain();
+ stats.writeToParcel(parcel);
+ parcel.writeString("END");
+
+ Parcel newParcel = marshallAndUnmarshall(parcel);
+
+ PowerStats newStats = PowerStats.readFromParcel(newParcel, mRegistry);
+ assertThat(newStats).isNull();
+
+ String end = newParcel.readString();
+ assertThat(end).isEqualTo("END");
+ }
+
+ @Test
+ public void parceling_wrongArrayLength() {
+ PowerStats stats = new PowerStats(mDescriptor);
+ stats.stats = new long[5]; // Is expected to be 3
+
+ Parcel parcel = Parcel.obtain();
+ stats.writeToParcel(parcel);
+ parcel.writeString("END");
+
+ Parcel newParcel = marshallAndUnmarshall(parcel);
+
+ PowerStats newStats = PowerStats.readFromParcel(newParcel, mRegistry);
+ assertThat(newStats).isNull();
+
+ String end = newParcel.readString();
+ assertThat(end).isEqualTo("END");
+ }
+
+ private static Parcel marshallAndUnmarshall(Parcel parcel) {
+ byte[] bytes = parcel.marshall();
+ parcel.recycle();
+
+ Parcel newParcel = Parcel.obtain();
+ newParcel.unmarshall(bytes, 0, bytes.length);
+ newParcel.setDataPosition(0);
+ return newParcel;
+ }
+}
diff --git a/core/tests/utiltests/src/android/util/IntArrayTest.java b/core/tests/utiltests/src/android/util/IntArrayTest.java
index caa7312a4475..ad5c4ee83e54 100644
--- a/core/tests/utiltests/src/android/util/IntArrayTest.java
+++ b/core/tests/utiltests/src/android/util/IntArrayTest.java
@@ -55,9 +55,11 @@ public class IntArrayTest {
a.add(5, 20);
assertThat(a.get(5)).isEqualTo(20);
assertThat(a.indexOf(20)).isEqualTo(5);
+ assertThat(a.contains(20)).isTrue();
verify(a, 1, 2, 0, 0, 0, 20, 10, 0, 0);
assertThat(a.indexOf(99)).isEqualTo(-1);
+ assertThat(a.contains(99)).isFalse();
a.resize(15);
a.set(14, 30);
@@ -71,6 +73,7 @@ public class IntArrayTest {
backingArray[2] = 30;
verify(a, backingArray);
assertThat(a.indexOf(30)).isEqualTo(2);
+ assertThat(a.contains(30)).isTrue();
a.resize(2);
assertThat(backingArray[2]).isEqualTo(0);
diff --git a/core/tests/vibrator/src/android/os/VibratorInfoTest.java b/core/tests/vibrator/src/android/os/VibratorInfoTest.java
index 808c4ece9435..73cd4647415d 100644
--- a/core/tests/vibrator/src/android/os/VibratorInfoTest.java
+++ b/core/tests/vibrator/src/android/os/VibratorInfoTest.java
@@ -257,8 +257,13 @@ public class VibratorInfoTest {
@Test
public void testEquals() {
- VibratorInfo.Builder completeBuilder = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
- .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
+ VibratorInfo.Builder completeBuilder = new VibratorInfo.Builder(TEST_VIBRATOR_ID);
+ // Create a builder with a different ID, but same properties the same as the first one.
+ VibratorInfo.Builder completeBuilder2 = new VibratorInfo.Builder(TEST_VIBRATOR_ID + 2);
+
+ for (VibratorInfo.Builder builder :
+ new VibratorInfo.Builder[] {completeBuilder, completeBuilder2}) {
+ builder.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
.setSupportedEffects(VibrationEffect.EFFECT_CLICK)
.setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
.setPrimitiveDelayMax(100)
@@ -268,31 +273,43 @@ public class VibratorInfoTest {
.setPwleSizeMax(20)
.setQFactor(2f)
.setFrequencyProfile(TEST_FREQUENCY_PROFILE);
+ }
VibratorInfo complete = completeBuilder.build();
assertEquals(complete, complete);
+ assertTrue(complete.equalContent(complete));
assertEquals(complete, completeBuilder.build());
+ assertTrue(complete.equalContent(completeBuilder.build()));
assertEquals(complete.hashCode(), completeBuilder.build().hashCode());
+ // The infos from the two builders should have equal content, but should not be equal due to
+ // their different IDs.
+ assertNotEquals(complete, completeBuilder2.build());
+ assertTrue(complete.equalContent(completeBuilder2.build()));
+
VibratorInfo completeWithComposeControl = completeBuilder
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
.build();
assertNotEquals(complete, completeWithComposeControl);
+ assertFalse(complete.equalContent(completeWithComposeControl));
VibratorInfo completeWithNoEffects = completeBuilder
.setSupportedEffects(new int[0])
.build();
assertNotEquals(complete, completeWithNoEffects);
+ assertFalse(complete.equalContent(completeWithNoEffects));
VibratorInfo completeWithUnknownEffects = completeBuilder
.setSupportedEffects(null)
.build();
assertNotEquals(complete, completeWithUnknownEffects);
+ assertFalse(complete.equalContent(completeWithUnknownEffects));
VibratorInfo completeWithDifferentPrimitiveDuration = completeBuilder
.setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
.build();
assertNotEquals(complete, completeWithDifferentPrimitiveDuration);
+ assertFalse(complete.equalContent(completeWithDifferentPrimitiveDuration));
VibratorInfo completeWithDifferentFrequencyProfile = completeBuilder
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(
@@ -302,31 +319,37 @@ public class VibratorInfoTest {
TEST_AMPLITUDE_MAP))
.build();
assertNotEquals(complete, completeWithDifferentFrequencyProfile);
+ assertFalse(complete.equalContent(completeWithDifferentFrequencyProfile));
VibratorInfo completeWithEmptyFrequencyProfile = completeBuilder
.setFrequencyProfile(EMPTY_FREQUENCY_PROFILE)
.build();
assertNotEquals(complete, completeWithEmptyFrequencyProfile);
+ assertFalse(complete.equalContent(completeWithEmptyFrequencyProfile));
VibratorInfo completeWithUnknownQFactor = completeBuilder.setQFactor(Float.NaN).build();
assertNotEquals(complete, completeWithUnknownQFactor);
+ assertFalse(complete.equalContent(completeWithUnknownQFactor));
VibratorInfo completeWithDifferentQFactor = completeBuilder
.setQFactor(complete.getQFactor() + 3f)
.build();
assertNotEquals(complete, completeWithDifferentQFactor);
+ assertFalse(complete.equalContent(completeWithDifferentQFactor));
VibratorInfo unknownEffectSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
VibratorInfo knownEmptyEffectSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
.setSupportedEffects(new int[0])
.build();
assertNotEquals(unknownEffectSupport, knownEmptyEffectSupport);
+ assertFalse(unknownEffectSupport.equalContent(knownEmptyEffectSupport));
VibratorInfo unknownBrakingSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
VibratorInfo knownEmptyBrakingSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
.setSupportedBraking(new int[0])
.build();
assertNotEquals(unknownBrakingSupport, knownEmptyBrakingSupport);
+ assertFalse(unknownBrakingSupport.equalContent(knownEmptyBrakingSupport));
}
@Test
diff --git a/core/tests/vibrator/src/android/os/VibratorTest.java b/core/tests/vibrator/src/android/os/VibratorTest.java
index 8141ca4b22a8..cfa12bb5b504 100644
--- a/core/tests/vibrator/src/android/os/VibratorTest.java
+++ b/core/tests/vibrator/src/android/os/VibratorTest.java
@@ -37,7 +37,6 @@ import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
-import android.hardware.vibrator.IVibrator;
import android.media.AudioAttributes;
import android.os.test.TestLooper;
@@ -60,8 +59,6 @@ public class VibratorTest {
@Rule
public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
- private static final float TEST_TOLERANCE = 1e-5f;
-
private Context mContextSpy;
private Vibrator mVibratorSpy;
private TestLooper mTestLooper;
@@ -79,9 +76,6 @@ public class VibratorTest {
@Test
public void getId_returnsDefaultId() {
assertEquals(-1, mVibratorSpy.getId());
- assertEquals(-1, new SystemVibrator.NoVibratorInfo().getId());
- assertEquals(-1, new SystemVibrator.MultiVibratorInfo(new VibratorInfo[] {
- VibratorInfo.EMPTY_VIBRATOR_INFO, VibratorInfo.EMPTY_VIBRATOR_INFO }).getId());
}
@Test
@@ -95,53 +89,6 @@ public class VibratorTest {
}
@Test
- public void areEffectsSupported_noVibrator_returnsAlwaysNo() {
- VibratorInfo info = new SystemVibrator.NoVibratorInfo();
- assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
- info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
- }
-
- @Test
- public void areEffectsSupported_unsupportedInOneVibrator_returnsNo() {
- VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
- .build();
- VibratorInfo unsupportedVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setSupportedEffects(new int[0])
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
- assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
- info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
- }
-
- @Test
- public void areEffectsSupported_unknownInOneVibrator_returnsUnknown() {
- VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
- .build();
- VibratorInfo unknownSupportVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{supportedVibrator, unknownSupportVibrator});
- assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN,
- info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
- }
-
- @Test
- public void arePrimitivesSupported_supportedInAllVibrators_returnsYes() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
- .build();
- VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, secondVibrator});
- assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
- info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
- }
-
- @Test
public void arePrimitivesSupported_returnsArrayOfSameSize() {
assertEquals(0, mVibratorSpy.arePrimitivesSupported(new int[0]).length);
assertEquals(1, mVibratorSpy.arePrimitivesSupported(
@@ -152,39 +99,6 @@ public class VibratorTest {
}
@Test
- public void arePrimitivesSupported_noVibrator_returnsAlwaysFalse() {
- VibratorInfo info = new SystemVibrator.NoVibratorInfo();
- assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
- }
-
- @Test
- public void arePrimitivesSupported_unsupportedInOneVibrator_returnsFalse() {
- VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
- .build();
- VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
- assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
- }
-
- @Test
- public void arePrimitivesSupported_supportedInAllVibrators_returnsTrue() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 5)
- .build();
- VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 15)
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, secondVibrator});
- assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
- }
-
- @Test
public void getPrimitivesDurations_returnsArrayOfSameSize() {
assertEquals(0, mVibratorSpy.getPrimitiveDurations(new int[0]).length);
assertEquals(1, mVibratorSpy.getPrimitiveDurations(
@@ -195,245 +109,6 @@ public class VibratorTest {
}
@Test
- public void getPrimitivesDurations_noVibrator_returnsAlwaysZero() {
- VibratorInfo info = new SystemVibrator.NoVibratorInfo();
- assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
- }
-
- @Test
- public void getPrimitivesDurations_unsupportedInOneVibrator_returnsZero() {
- VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
- .build();
- VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
- assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
- }
-
- @Test
- public void getPrimitivesDurations_supportedInAllVibrators_returnsMaxDuration() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
- .build();
- VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, secondVibrator});
- assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
- }
-
- @Test
- public void getQFactorAndResonantFrequency_noVibrator_returnsNaN() {
- VibratorInfo info = new SystemVibrator.NoVibratorInfo();
-
- assertTrue(Float.isNaN(info.getQFactor()));
- assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
- }
-
- @Test
- public void getQFactorAndResonantFrequency_differentValues_returnsNaN() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setQFactor(1f)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
- .build();
- VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setQFactor(2f)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 2, 2, null))
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, secondVibrator});
-
- assertTrue(Float.isNaN(info.getQFactor()));
- assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
- assertEmptyFrequencyProfileAndControl(info);
-
- // One vibrator with values undefined.
- VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3).build();
- info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, thirdVibrator});
-
- assertTrue(Float.isNaN(info.getQFactor()));
- assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
- assertEmptyFrequencyProfileAndControl(info);
- }
-
- @Test
- public void getQFactorAndResonantFrequency_sameValues_returnsValue() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setQFactor(10f)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
- /* resonantFrequencyHz= */ 11, 10, 0.5f, null))
- .build();
- VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setQFactor(10f)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
- /* resonantFrequencyHz= */ 11, 5, 1, null))
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, secondVibrator});
-
- assertEquals(10f, info.getQFactor(), TEST_TOLERANCE);
- assertEquals(11f, info.getResonantFrequencyHz(), TEST_TOLERANCE);
-
- // No frequency range defined.
- assertTrue(info.getFrequencyProfile().isEmpty());
- assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
- }
-
- @Test
- public void getFrequencyProfile_noVibrator_returnsEmpty() {
- VibratorInfo info = new SystemVibrator.NoVibratorInfo();
-
- assertEmptyFrequencyProfileAndControl(info);
- }
-
- @Test
- public void getFrequencyProfile_differentResonantFrequencyOrResolutionValues_returnsEmpty() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
- new float[] { 0, 1 }))
- .build();
- VibratorInfo differentResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 1, 1,
- new float[] { 0, 1 }))
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, differentResonantFrequency});
-
- assertEmptyFrequencyProfileAndControl(info);
-
- VibratorInfo differentFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 2,
- new float[] { 0, 1 }))
- .build();
- info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, differentFrequencyResolution});
-
- assertEmptyFrequencyProfileAndControl(info);
- }
-
- @Test
- public void getFrequencyProfile_missingValues_returnsEmpty() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
- new float[] { 0, 1 }))
- .build();
- VibratorInfo missingResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(Float.NaN, 1, 1,
- new float[] { 0, 1 }))
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, missingResonantFrequency});
-
- assertEmptyFrequencyProfileAndControl(info);
-
- VibratorInfo missingMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, Float.NaN, 1,
- new float[] { 0, 1 }))
- .build();
- info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, missingMinFrequency});
-
- assertEmptyFrequencyProfileAndControl(info);
-
- VibratorInfo missingFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, Float.NaN,
- new float[] { 0, 1 }))
- .build();
- info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, missingFrequencyResolution});
-
- assertEmptyFrequencyProfileAndControl(info);
-
- VibratorInfo missingMaxAmplitudes = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
- .build();
- info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, missingMaxAmplitudes});
-
- assertEmptyFrequencyProfileAndControl(info);
- }
-
- @Test
- public void getFrequencyProfile_unalignedMaxAmplitudes_returnsEmpty() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
- new float[] { 0, 1, 1, 0 }))
- .build();
- VibratorInfo unalignedMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.1f, 0.5f,
- new float[] { 0, 1, 1, 0 }))
- .build();
- VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
- new float[] { 0, 1, 1, 0 }))
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, unalignedMinFrequency, thirdVibrator});
-
- assertEmptyFrequencyProfileAndControl(info);
- }
-
- @Test
- public void getFrequencyProfile_alignedProfiles_returnsIntersection() {
- VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
- new float[] { 0.5f, 1, 1, 0.5f }))
- .build();
- VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
- new float[] { 1, 1, 1 }))
- .build();
- VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
- .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
- new float[] { 0.8f, 1, 0.8f, 0.5f }))
- .build();
- VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, secondVibrator, thirdVibrator});
-
- assertEquals(
- new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
- info.getFrequencyProfile());
- assertEquals(true, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
-
- // Third vibrator without frequency control capability.
- thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
- .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
- new float[] { 0.8f, 1, 0.8f, 0.5f }))
- .build();
- info = new SystemVibrator.MultiVibratorInfo(
- new VibratorInfo[]{firstVibrator, secondVibrator, thirdVibrator});
-
- assertEquals(
- new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
- info.getFrequencyProfile());
- assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
- }
-
- @Test
public void onVibratorStateChanged_noVibrator_registersNoListenerToVibratorManager() {
VibratorManager mockVibratorManager = mock(VibratorManager.class);
when(mockVibratorManager.getVibratorIds()).thenReturn(new int[0]);
@@ -577,12 +252,4 @@ public class VibratorTest {
VibrationAttributes vibrationAttributes = captor.getValue();
assertEquals(new VibrationAttributes.Builder().build(), vibrationAttributes);
}
-
- /**
- * Asserts that the frequency profile is empty, and therefore frequency control isn't supported.
- */
- void assertEmptyFrequencyProfileAndControl(VibratorInfo info) {
- assertTrue(info.getFrequencyProfile().isEmpty());
- assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
- }
}
diff --git a/core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java b/core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java
new file mode 100644
index 000000000000..fc31ac44b362
--- /dev/null
+++ b/core/tests/vibrator/src/android/os/vibrator/MultiVibratorInfoTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.vibrator;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.assertEquals;
+
+import android.hardware.vibrator.IVibrator;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.os.VibratorInfo;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class MultiVibratorInfoTest {
+ private static final float TEST_TOLERANCE = 1e-5f;
+
+ @Test
+ public void testGetId() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setSupportedEffects(new int[0])
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 3,
+ new VibratorInfo[]{firstInfo, secondInfo});
+
+ assertEquals(3, info.getId());
+ }
+
+ @Test
+ public void testIsEffectSupported_supportedInAllVibrators_returnsYes() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK)
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, secondInfo});
+
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void testIsEffectSupported_unsupportedInOneVibrator_returnsNo() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo unsupportedVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setSupportedEffects(new int[0])
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void testIsEffectSupported_unknownInOneVibrator_returnsUnknown() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo unknownSupportVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{supportedVibrator, unknownSupportVibrator});
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void testIsPrimitiveSupported_unsupportedInOneVibrator_returnsFalse() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+
+ assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void testIsPrimitiveSupported_supportedInAllVibrators_returnsTrue() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 5)
+ .build();
+ VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 15)
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, secondInfo});
+
+ assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void testGetPrimitiveDuration_unsupportedInOneVibrator_returnsZero() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+
+ assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void testGetPrimitiveDuration_supportedInAllVibrators_returnsMaxDuration() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, secondInfo});
+
+ assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void testGetQFactorAndResonantFrequency_differentValues_returnsNaN() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setQFactor(1f)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
+ .build();
+ VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setQFactor(2f)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 2, 2, null))
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, secondInfo});
+
+ assertTrue(Float.isNaN(info.getQFactor()));
+ assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
+ assertEmptyFrequencyProfileAndControl(info);
+
+ // One vibrator with values undefined.
+ VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3).build();
+ info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, thirdVibrator});
+
+ assertTrue(Float.isNaN(info.getQFactor()));
+ assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
+ assertEmptyFrequencyProfileAndControl(info);
+ }
+
+ @Test
+ public void testGetQFactorAndResonantFrequency_sameValues_returnsValue() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setQFactor(10f)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
+ /* resonantFrequencyHz= */ 11, 10, 0.5f, null))
+ .build();
+ VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setQFactor(10f)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
+ /* resonantFrequencyHz= */ 11, 5, 1, null))
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, secondInfo});
+
+ assertEquals(10f, info.getQFactor(), TEST_TOLERANCE);
+ assertEquals(11f, info.getResonantFrequencyHz(), TEST_TOLERANCE);
+ // No frequency range defined.
+ assertTrue(info.getFrequencyProfile().isEmpty());
+ assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
+ }
+
+ @Test
+ public void testGetFrequencyProfile_differentResonantFrequencyOrResolutions_returnsEmpty() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
+ new float[] { 0, 1 }))
+ .build();
+ VibratorInfo differentResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 1, 1,
+ new float[] { 0, 1 }))
+ .build();
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, differentResonantFrequency});
+
+ assertEmptyFrequencyProfileAndControl(info);
+
+ VibratorInfo differentFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 2,
+ new float[] { 0, 1 }))
+ .build();
+ info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, differentFrequencyResolution});
+
+ assertEmptyFrequencyProfileAndControl(info);
+ }
+
+ @Test
+ public void testGetFrequencyProfile_missingValues_returnsEmpty() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
+ new float[] { 0, 1 }))
+ .build();
+ VibratorInfo missingResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(Float.NaN, 1, 1,
+ new float[] { 0, 1 }))
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, missingResonantFrequency});
+
+ assertEmptyFrequencyProfileAndControl(info);
+
+ VibratorInfo missingMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, Float.NaN, 1,
+ new float[] { 0, 1 }))
+ .build();
+ info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, missingMinFrequency});
+
+ assertEmptyFrequencyProfileAndControl(info);
+
+ VibratorInfo missingFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, Float.NaN,
+ new float[] { 0, 1 }))
+ .build();
+ info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, missingFrequencyResolution});
+
+ assertEmptyFrequencyProfileAndControl(info);
+
+ VibratorInfo missingMaxAmplitudes = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
+ .build();
+ info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, missingMaxAmplitudes});
+
+ assertEmptyFrequencyProfileAndControl(info);
+ }
+
+ @Test
+ public void testGetFrequencyProfile_unalignedMaxAmplitudes_returnsEmpty() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
+ new float[] { 0, 1, 1, 0 }))
+ .build();
+ VibratorInfo unalignedMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.1f, 0.5f,
+ new float[] { 0, 1, 1, 0 }))
+ .build();
+ VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+ new float[] { 0, 1, 1, 0 }))
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, unalignedMinFrequency, thirdVibrator});
+
+ assertEmptyFrequencyProfileAndControl(info);
+ }
+
+ @Test
+ public void testGetFrequencyProfile_alignedProfiles_returnsIntersection() {
+ VibratorInfo firstInfo = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
+ new float[] { 0.5f, 1, 1, 0.5f }))
+ .build();
+ VibratorInfo secondInfo = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+ new float[] { 1, 1, 1 }))
+ .build();
+ VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+ new float[] { 0.8f, 1, 0.8f, 0.5f }))
+ .build();
+
+ VibratorInfo info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, secondInfo, thirdVibrator});
+
+ assertEquals(
+ new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
+ info.getFrequencyProfile());
+ assertEquals(true, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
+
+ // Third vibrator without frequency control capability.
+ thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
+ .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
+ new float[] { 0.8f, 1, 0.8f, 0.5f }))
+ .build();
+ info = new MultiVibratorInfo(/* id= */ 1,
+ new VibratorInfo[]{firstInfo, secondInfo, thirdVibrator});
+
+ assertEquals(
+ new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
+ info.getFrequencyProfile());
+ assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
+ }
+
+ /**
+ * Asserts that the frequency profile is empty, and therefore frequency control isn't supported.
+ */
+ private void assertEmptyFrequencyProfileAndControl(VibratorInfo info) {
+ assertTrue(info.getFrequencyProfile().isEmpty());
+ assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
+ }
+}
diff --git a/core/tests/vibrator/src/android/os/vibrator/VibratorInfoFactoryTest.java b/core/tests/vibrator/src/android/os/vibrator/VibratorInfoFactoryTest.java
new file mode 100644
index 000000000000..df4822fc8b04
--- /dev/null
+++ b/core/tests/vibrator/src/android/os/vibrator/VibratorInfoFactoryTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.vibrator;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.assertEquals;
+
+import android.hardware.vibrator.IVibrator;
+import android.os.VibrationEffect;
+import android.os.VibratorInfo;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class VibratorInfoFactoryTest {
+
+ @Test
+ public void testCreatedInfo_hasTheRequestedId() {
+ // Empty info list.
+ VibratorInfo infoFromEmptyInfos =
+ VibratorInfoFactory.create(/* id= */ 3, new VibratorInfo[] {});
+ VibratorInfo info1 = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo info2 = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo infoFromOneInfo =
+ VibratorInfoFactory.create(/* id= */ -1, new VibratorInfo[] {info1});
+ VibratorInfo infoFromTwoInfos =
+ VibratorInfoFactory.create(/* id= */ -3, new VibratorInfo[] {info1, info2});
+
+ assertEquals(3, infoFromEmptyInfos.getId());
+ assertEquals(-1, infoFromOneInfo.getId());
+ assertEquals(-3, infoFromTwoInfos.getId());
+ }
+
+ @Test
+ public void testCreatedInfo_fromEmptyVibratorInfos_returnsEmptyVibratorInfo() {
+ VibratorInfo info = VibratorInfoFactory.create(/* id= */ 2, new VibratorInfo[] {});
+
+ assertEqualContent(VibratorInfo.EMPTY_VIBRATOR_INFO, info);
+ }
+
+ @Test
+ public void testCreatedInfo_fromSingleVibratorInfo_hasEqualContent() {
+ VibratorInfo info = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS | IVibrator.CAP_FREQUENCY_CONTROL)
+ .setSupportedEffects(VibrationEffect.EFFECT_TICK, VibrationEffect.EFFECT_THUD)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 30)
+ .build();
+
+ VibratorInfo createdInfo =
+ VibratorInfoFactory.create(/* id= */ -1, new VibratorInfo[] {info});
+
+ assertEqualContent(info, createdInfo);
+ }
+
+ @Test
+ public void testCreatedInfo_hasEqualContentRegardlessOfSourceInfoOrder() {
+ VibratorInfo info1 = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo info2 = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+
+ assertEqualContent(
+ VibratorInfoFactory.create(/* id= */ -1, new VibratorInfo[] {info1, info2}),
+ VibratorInfoFactory.create(/* id= */ -1, new VibratorInfo[] {info2, info1}));
+ }
+
+ @Test
+ public void testCreatedInfoContents() {
+ VibratorInfo info1 = new VibratorInfo.Builder(/* id= */ -1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS | IVibrator.CAP_FREQUENCY_CONTROL)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_POP)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_THUD, 5)
+ .build();
+ VibratorInfo info2 = new VibratorInfo.Builder(/* id= */ -2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS | IVibrator.CAP_AMPLITUDE_CONTROL)
+ .setSupportedEffects(VibrationEffect.EFFECT_POP, VibrationEffect.EFFECT_THUD)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_THUD, 20)
+ .build();
+ VibratorInfo info3 = new VibratorInfo.Builder(/* id= */ -3)
+ .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
+ .build();
+
+ assertEquals(
+ new VibratorInfo.Builder(/* id= */ 3)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedEffects(VibrationEffect.EFFECT_POP)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_THUD, 20)
+ .build(),
+ VibratorInfoFactory.create(/* id= */ 3, new VibratorInfo[] {info1, info2}));
+ assertEquals(
+ new VibratorInfo.Builder(/* id= */ 3)
+ .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
+ .build(),
+ VibratorInfoFactory.create(/* id= */ 3, new VibratorInfo[] {info2, info3}));
+ assertEquals(
+ new VibratorInfo.Builder(/* id= */ 3).build(),
+ VibratorInfoFactory.create(/* id= */ 3, new VibratorInfo[] {info1, info3}));
+ }
+
+ private static void assertEqualContent(VibratorInfo info1, VibratorInfo info2) {
+ assertTrue(info1.equalContent(info2));
+ }
+}
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
new file mode 100644
index 000000000000..a0a06f1b3721
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<com.android.wm.shell.common.bubbles.BubblePopupView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginHorizontal="@dimen/bubble_popup_margin_horizontal"
+ android:layout_marginTop="@dimen/bubble_popup_margin_top"
+ android:elevation="@dimen/bubble_manage_menu_elevation"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:tint="?android:attr/colorAccent"
+ android:contentDescription="@null"
+ android:src="@drawable/pip_ic_settings"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:maxWidth="@dimen/bubble_popup_content_max_width"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/bubble_bar_education_manage_title"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:maxWidth="@dimen/bubble_popup_content_max_width"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAlignment="center"
+ android:text="@string/bubble_bar_education_manage_text"/>
+
+</com.android.wm.shell.common.bubbles.BubblePopupView> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 597e899d098d..20bf81da5561 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -226,6 +226,20 @@
<dimen name="bubble_user_education_padding_end">58dp</dimen>
<!-- Padding between the bubble and the user education text. -->
<dimen name="bubble_user_education_stack_padding">16dp</dimen>
+ <!-- Max width for the bubble popup view. -->
+ <dimen name="bubble_popup_content_max_width">300dp</dimen>
+ <!-- Horizontal margin for the bubble popup view. -->
+ <dimen name="bubble_popup_margin_horizontal">32dp</dimen>
+ <!-- Top margin for the bubble popup view. -->
+ <dimen name="bubble_popup_margin_top">16dp</dimen>
+ <!-- Width for the bubble popup view arrow. -->
+ <dimen name="bubble_popup_arrow_width">12dp</dimen>
+ <!-- Height for the bubble popup view arrow. -->
+ <dimen name="bubble_popup_arrow_height">10dp</dimen>
+ <!-- Corner radius for the bubble popup view arrow. -->
+ <dimen name="bubble_popup_arrow_corner_radius">2dp</dimen>
+ <!-- Padding for the bubble popup view contents. -->
+ <dimen name="bubble_popup_padding">24dp</dimen>
<!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
<dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
<!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 8cbc3d016b01..00c63d70d3a0 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -163,6 +163,11 @@
<!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
<string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>
+ <!-- Title text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
+ <string name="bubble_bar_education_manage_title">Control bubbles anytime</string>
+ <!-- Descriptive text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
+ <string name="bubble_bar_education_manage_text">Tap here to manage which apps and conversations can bubble</string>
+
<!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_bubble_title">Bubble</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 7e09c989e1b3..ff67110634ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -60,7 +60,6 @@ import java.util.concurrent.Executor;
/**
* Encapsulates the data and UI elements of a bubble.
*/
-@VisibleForTesting
public class Bubble implements BubbleViewProvider {
private static final String TAG = "Bubble";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
new file mode 100644
index 000000000000..e57f02c71e44
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.bubbles
+
+import android.content.Context
+import android.util.Log
+import androidx.core.content.edit
+import com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION
+import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES
+import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
+
+/** Manages bubble education flags. Provides convenience methods to check the education state */
+class BubbleEducationController(private val context: Context) {
+ private val prefs = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
+
+ /** Whether the user has seen the stack education */
+ @get:JvmName(name = "hasSeenStackEducation")
+ var hasSeenStackEducation: Boolean
+ get() = prefs.getBoolean(PREF_STACK_EDUCATION, false)
+ set(value) = prefs.edit { putBoolean(PREF_STACK_EDUCATION, value) }
+
+ /** Whether the user has seen the expanded view "manage" menu education */
+ @get:JvmName(name = "hasSeenManageEducation")
+ var hasSeenManageEducation: Boolean
+ get() = prefs.getBoolean(PREF_MANAGED_EDUCATION, false)
+ set(value) = prefs.edit { putBoolean(PREF_MANAGED_EDUCATION, value) }
+
+ /** Whether education view should show for the collapsed stack. */
+ fun shouldShowStackEducation(bubble: BubbleViewProvider?): Boolean {
+ val shouldShow = bubble != null &&
+ bubble.isConversationBubble && // show education for conversation bubbles only
+ (!hasSeenStackEducation || BubbleDebugConfig.forceShowUserEducation(context))
+ logDebug("Show stack edu: $shouldShow")
+ return shouldShow
+ }
+
+ /** Whether the educational view should show for the expanded view "manage" menu. */
+ fun shouldShowManageEducation(bubble: BubbleViewProvider?): Boolean {
+ val shouldShow = bubble != null &&
+ bubble.isConversationBubble && // show education for conversation bubbles only
+ (!hasSeenManageEducation || BubbleDebugConfig.forceShowUserEducation(context))
+ logDebug("Show manage edu: $shouldShow")
+ return shouldShow
+ }
+
+ private fun logDebug(message: String) {
+ if (DEBUG_USER_EDUCATION) {
+ Log.d(TAG, message)
+ }
+ }
+
+ companion object {
+ private val TAG = if (TAG_WITH_CLASS_NAME) "BubbleEducationController" else TAG_BUBBLES
+ const val PREF_STACK_EDUCATION: String = "HasSeenBubblesOnboarding"
+ const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding"
+ }
+}
+
+/** Convenience extension method to check if the bubble is a conversation bubble */
+private val BubbleViewProvider.isConversationBubble: Boolean
+ get() = if (this is Bubble) isConversation else false
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt
new file mode 100644
index 000000000000..bdb09e11d5ad
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.bubbles
+
+import android.graphics.Color
+import com.android.wm.shell.R
+import com.android.wm.shell.common.bubbles.BubblePopupDrawable
+import com.android.wm.shell.common.bubbles.BubblePopupView
+
+/**
+ * A convenience method to setup the [BubblePopupView] with the correct config using local resources
+ */
+fun BubblePopupView.setup() {
+ val attrs =
+ context.obtainStyledAttributes(
+ intArrayOf(
+ com.android.internal.R.attr.materialColorSurface,
+ android.R.attr.dialogCornerRadius
+ )
+ )
+
+ val res = context.resources
+ val config =
+ BubblePopupDrawable.Config(
+ color = attrs.getColor(0, Color.WHITE),
+ cornerRadius = attrs.getDimension(1, 0f),
+ contentPadding = res.getDimensionPixelSize(R.dimen.bubble_popup_padding),
+ arrowWidth = res.getDimension(R.dimen.bubble_popup_arrow_width),
+ arrowHeight = res.getDimension(R.dimen.bubble_popup_arrow_height),
+ arrowRadius = res.getDimension(R.dimen.bubble_popup_arrow_corner_radius)
+ )
+ attrs.recycle()
+ setupBackground(config)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index da5974fe3dc2..8ae12c75b3ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -46,7 +46,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
-import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
@@ -108,12 +107,6 @@ import java.util.stream.Collectors;
*/
public class BubbleStackView extends FrameLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
-
- // LINT.IfChange
- public static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
- SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
- // LINT.ThenChange(com/android/launcher3/taskbar/bubbles/BubbleDismissController.java)
-
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
/** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
@@ -138,7 +131,7 @@ public class BubbleStackView extends FrameLayout
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
- private static final float SCRIM_ALPHA = 0.6f;
+ private static final float SCRIM_ALPHA = 0.32f;
/** Minimum alpha value for scrim when alpha is being changed via drag */
private static final float MIN_SCRIM_ALPHA_FOR_DRAG = 0.2f;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 33629f9f4622..c20733af2ba5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -19,7 +19,6 @@ package com.android.wm.shell.bubbles.animation;
import static android.view.View.LAYOUT_DIRECTION_RTL;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
-import static com.android.wm.shell.bubbles.BubbleStackView.ENABLE_FLING_TO_DISMISS_BUBBLE;
import android.content.res.Resources;
import android.graphics.Path;
@@ -355,7 +354,6 @@ public class ExpandedAnimationController
mMagnetizedBubbleDraggingOut.setMagnetListener(listener);
mMagnetizedBubbleDraggingOut.setHapticsEnabled(true);
mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
- mMagnetizedBubbleDraggingOut.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
}
private void springBubbleTo(View bubble, float x, float y) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 5533842f2d89..4bb1ab4d0f54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -17,7 +17,6 @@
package com.android.wm.shell.bubbles.animation;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
-import static com.android.wm.shell.bubbles.BubbleStackView.ENABLE_FLING_TO_DISMISS_BUBBLE;
import android.content.ContentResolver;
import android.content.res.Resources;
@@ -1026,7 +1025,6 @@ public class StackAnimationController extends
};
mMagnetizedStack.setHapticsEnabled(true);
mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
- mMagnetizedStack.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
}
final ContentResolver contentResolver = mLayout.getContext().getContentResolver();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 6b6d6baa3d39..79f188ab2611 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -39,7 +39,6 @@ import com.android.wm.shell.bubbles.BubbleTaskViewHelper;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.taskview.TaskView;
-import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -48,6 +47,18 @@ import java.util.function.Supplier;
* {@link BubbleController#isShowingAsBubbleBar()}
*/
public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewHelper.Listener {
+ /**
+ * The expanded view listener notifying the {@link BubbleBarLayerView} about the internal
+ * actions and events
+ */
+ public interface Listener {
+ /** Called when the task view task is first created. */
+ void onTaskCreated();
+ /** Called when expanded view needs to un-bubble the given conversation */
+ void onUnBubbleConversation(String bubbleKey);
+ /** Called when expanded view task view back button pressed */
+ void onBackPressed();
+ }
private static final String TAG = BubbleBarExpandedView.class.getSimpleName();
private static final int INVALID_TASK_ID = -1;
@@ -57,7 +68,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
private BubbleTaskViewHelper mBubbleTaskViewHelper;
private BubbleBarMenuViewController mMenuViewController;
private @Nullable Supplier<Rect> mLayerBoundsSupplier;
- private @Nullable Consumer<String> mUnBubbleConversationCallback;
+ private @Nullable Listener mListener;
private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
private @Nullable TaskView mTaskView;
@@ -145,15 +156,13 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
@Override
public void onMenuVisibilityChanged(boolean visible) {
- if (mTaskView == null || mLayerBoundsSupplier == null) return;
- // Updates the obscured touchable region for the task surface.
- mTaskView.setObscuredTouchRect(visible ? mLayerBoundsSupplier.get() : null);
+ setObscured(visible);
}
@Override
public void onUnBubbleConversation(Bubble bubble) {
- if (mUnBubbleConversationCallback != null) {
- mUnBubbleConversationCallback.accept(bubble.getKey());
+ if (mListener != null) {
+ mListener.onUnBubbleConversation(bubble.getKey());
}
}
@@ -231,6 +240,9 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
public void onTaskCreated() {
setContentVisibility(true);
updateHandleColor(false /* animated */);
+ if (mListener != null) {
+ mListener.onTaskCreated();
+ }
}
@Override
@@ -240,7 +252,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
@Override
public void onBackPressed() {
- mController.collapseStack();
+ if (mListener == null) return;
+ mListener.onBackPressed();
}
/** Cleans up task view, should be called when the bubble is no longer active. */
@@ -254,6 +267,18 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
mMenuViewController.hideMenu(false /* animated */);
}
+ /**
+ * Hides the current modal menu view or collapses the bubble stack.
+ * Called from {@link BubbleBarLayerView}
+ */
+ public void hideMenuOrCollapse() {
+ if (mMenuViewController.isMenuVisible()) {
+ mMenuViewController.hideMenu(/* animated = */ true);
+ } else {
+ mController.collapseStack();
+ }
+ }
+
/** Updates the bubble shown in the expanded view. */
public void update(Bubble bubble) {
mBubbleTaskViewHelper.update(bubble);
@@ -270,10 +295,16 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
mLayerBoundsSupplier = supplier;
}
- /** Sets the function to call to un-bubble the given conversation. */
- public void setUnBubbleConversationCallback(
- @Nullable Consumer<String> unBubbleConversationCallback) {
- mUnBubbleConversationCallback = unBubbleConversationCallback;
+ /** Sets expanded view listener */
+ void setListener(@Nullable Listener listener) {
+ mListener = listener;
+ }
+
+ /** Sets whether the view is obscured by some modal view */
+ void setObscured(boolean obscured) {
+ if (mTaskView == null || mLayerBoundsSupplier == null) return;
+ // Updates the obscured touchable region for the task surface.
+ mTaskView.setObscuredTouchRect(obscured ? mLayerBoundsSupplier.get() : null);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index bc04bfc8c18b..8f11253290ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -52,6 +52,7 @@ public class BubbleBarLayerView extends FrameLayout
private final BubbleController mBubbleController;
private final BubblePositioner mPositioner;
private final BubbleBarAnimationHelper mAnimationHelper;
+ private final BubbleEducationViewController mEducationViewController;
private final View mScrimView;
@Nullable
@@ -80,6 +81,10 @@ public class BubbleBarLayerView extends FrameLayout
mAnimationHelper = new BubbleBarAnimationHelper(context,
this, mPositioner);
+ mEducationViewController = new BubbleEducationViewController(context, (boolean visible) -> {
+ if (mExpandedView == null) return;
+ mExpandedView.setObscured(visible);
+ });
mScrimView = new View(getContext());
mScrimView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -90,9 +95,7 @@ public class BubbleBarLayerView extends FrameLayout
mScrimView.setBackgroundDrawable(new ColorDrawable(
getResources().getColor(android.R.color.system_neutral1_1000)));
- setOnClickListener(view -> {
- mBubbleController.collapseStack();
- });
+ setOnClickListener(view -> hideMenuOrCollapse());
}
@Override
@@ -108,6 +111,7 @@ public class BubbleBarLayerView extends FrameLayout
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
if (mExpandedView != null) {
+ mEducationViewController.hideManageEducation(/* animated = */ false);
removeView(mExpandedView);
mExpandedView = null;
}
@@ -162,14 +166,27 @@ public class BubbleBarLayerView extends FrameLayout
final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
mExpandedView.setVisibility(GONE);
- mExpandedView.setUnBubbleConversationCallback(mUnBubbleConversationCallback);
+ mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
mExpandedView.setLayerBoundsSupplier(() -> new Rect(0, 0, getWidth(), getHeight()));
- mExpandedView.setUnBubbleConversationCallback(bubbleKey -> {
- if (mUnBubbleConversationCallback != null) {
- mUnBubbleConversationCallback.accept(bubbleKey);
+ mExpandedView.setListener(new BubbleBarExpandedView.Listener() {
+ @Override
+ public void onTaskCreated() {
+ mEducationViewController.maybeShowManageEducation(b, mExpandedView);
+ }
+
+ @Override
+ public void onUnBubbleConversation(String bubbleKey) {
+ if (mUnBubbleConversationCallback != null) {
+ mUnBubbleConversationCallback.accept(bubbleKey);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ hideMenuOrCollapse();
}
});
- mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
+
addView(mExpandedView, new FrameLayout.LayoutParams(width, height));
}
@@ -193,6 +210,7 @@ public class BubbleBarLayerView extends FrameLayout
public void collapse() {
mIsExpanded = false;
final BubbleBarExpandedView viewToRemove = mExpandedView;
+ mEducationViewController.hideManageEducation(/* animated = */ true);
mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
mBubbleController.getSysuiProxy().onStackExpandChanged(false);
mExpandedView = null;
@@ -206,6 +224,17 @@ public class BubbleBarLayerView extends FrameLayout
mUnBubbleConversationCallback = unBubbleConversationCallback;
}
+ /** Hides the current modal education/menu view, expanded view or collapses the bubble stack */
+ private void hideMenuOrCollapse() {
+ if (mEducationViewController.isManageEducationVisible()) {
+ mEducationViewController.hideManageEducation(/* animated = */ true);
+ } else if (isExpanded() && mExpandedView != null) {
+ mExpandedView.hideMenuOrCollapse();
+ } else {
+ mBubbleController.collapseStack();
+ }
+ }
+
/** Updates the expanded view size and position. */
private void updateExpandedView() {
if (mExpandedView == null) return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
index 8be140c16435..81e7582e0dba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
@@ -56,6 +56,11 @@ class BubbleBarMenuViewController {
SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
}
+ /** Tells if the menu is visible or being animated */
+ boolean isMenuVisible() {
+ return mMenuView != null && mMenuView.getVisibility() == View.VISIBLE;
+ }
+
/** Sets menu actions listener */
void setListener(@Nullable Listener listener) {
mListener = listener;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt
new file mode 100644
index 000000000000..7b39c6fd4059
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.bubbles.bar
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.view.doOnLayout
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.PhysicsAnimator
+import com.android.wm.shell.bubbles.BubbleEducationController
+import com.android.wm.shell.bubbles.BubbleViewProvider
+import com.android.wm.shell.bubbles.setup
+import com.android.wm.shell.common.bubbles.BubblePopupView
+
+/** Manages bubble education presentation and animation */
+class BubbleEducationViewController(private val context: Context, private val listener: Listener) {
+ interface Listener {
+ fun onManageEducationVisibilityChanged(isVisible: Boolean)
+ }
+
+ private var rootView: ViewGroup? = null
+ private var educationView: BubblePopupView? = null
+ private var animator: PhysicsAnimator<BubblePopupView>? = null
+
+ private val springConfig by lazy {
+ PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_MEDIUM,
+ SpringForce.DAMPING_RATIO_LOW_BOUNCY
+ )
+ }
+
+ private val controller by lazy { BubbleEducationController(context) }
+
+ /** Whether the education view is visible or being animated */
+ val isManageEducationVisible: Boolean
+ get() = educationView != null && rootView != null
+
+ /**
+ * Show manage bubble education if hasn't been shown before
+ *
+ * @param bubble the bubble used for the manage education check
+ * @param root the view to show manage education in
+ */
+ fun maybeShowManageEducation(bubble: BubbleViewProvider, root: ViewGroup) {
+ if (!controller.shouldShowManageEducation(bubble)) return
+ showManageEducation(root)
+ }
+
+ /**
+ * Hide the manage education view if visible
+ *
+ * @param animated whether should hide with animation
+ */
+ fun hideManageEducation(animated: Boolean) {
+ rootView?.let {
+ fun cleanUp() {
+ it.removeView(educationView)
+ rootView = null
+ listener.onManageEducationVisibilityChanged(isVisible = false)
+ }
+
+ if (animated) {
+ animateTransition(show = false, ::cleanUp)
+ } else {
+ cleanUp()
+ }
+ }
+ }
+
+ /**
+ * Show manage education with animation
+ *
+ * @param root the view to show manage education in
+ */
+ private fun showManageEducation(root: ViewGroup) {
+ hideManageEducation(animated = false)
+ if (educationView == null) {
+ val eduView = createEducationView(root)
+ educationView = eduView
+ animator = createAnimation(eduView)
+ }
+ root.addView(educationView)
+ rootView = root
+ animateTransition(show = true) {
+ controller.hasSeenManageEducation = true
+ listener.onManageEducationVisibilityChanged(isVisible = true)
+ }
+ }
+
+ /**
+ * Animate show/hide transition for the education view
+ *
+ * @param show whether to show or hide the view
+ * @param endActions a closure to be called when the animation completes
+ */
+ private fun animateTransition(show: Boolean, endActions: () -> Unit) {
+ animator?.let { animator ->
+ animator
+ .spring(DynamicAnimation.ALPHA, if (show) 1f else 0f)
+ .spring(DynamicAnimation.SCALE_X, if (show) 1f else EDU_SCALE_HIDDEN)
+ .spring(DynamicAnimation.SCALE_Y, if (show) 1f else EDU_SCALE_HIDDEN)
+ .withEndActions(endActions)
+ .start()
+ } ?: endActions()
+ }
+
+ private fun createEducationView(root: ViewGroup): BubblePopupView {
+ val view =
+ LayoutInflater.from(context).inflate(R.layout.bubble_bar_manage_education, root, false)
+ as BubblePopupView
+
+ return view.apply {
+ setup()
+ alpha = 0f
+ pivotY = 0f
+ scaleX = EDU_SCALE_HIDDEN
+ scaleY = EDU_SCALE_HIDDEN
+ doOnLayout { it.pivotX = it.width / 2f }
+ setOnClickListener { hideManageEducation(animated = true) }
+ }
+ }
+
+ private fun createAnimation(view: BubblePopupView): PhysicsAnimator<BubblePopupView> {
+ val animator = PhysicsAnimator.getInstance(view)
+ animator.setDefaultSpringConfig(springConfig)
+ return animator
+ }
+
+ companion object {
+ private const val EDU_SCALE_HIDDEN = 0.5f
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt
new file mode 100644
index 000000000000..8b5283d83683
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.common.bubbles
+
+import android.annotation.ColorInt
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Matrix
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import kotlin.math.atan
+import kotlin.math.cos
+import kotlin.math.sin
+import kotlin.properties.Delegates
+
+/** A drawable for the [BubblePopupView] that draws a popup background with a directional arrow */
+class BubblePopupDrawable(private val config: Config) : Drawable() {
+ /** The direction of the arrow in the popup drawable */
+ enum class ArrowDirection {
+ UP,
+ DOWN
+ }
+
+ /** The arrow position on the side of the popup bubble */
+ sealed class ArrowPosition {
+ object Start : ArrowPosition()
+ object Center : ArrowPosition()
+ object End : ArrowPosition()
+ class Custom(val value: Float) : ArrowPosition()
+ }
+
+ /** The configuration for drawable features */
+ data class Config(
+ @ColorInt val color: Int,
+ val cornerRadius: Float,
+ val contentPadding: Int,
+ val arrowWidth: Float,
+ val arrowHeight: Float,
+ val arrowRadius: Float
+ )
+
+ /**
+ * The direction of the arrow in the popup drawable. It affects the content padding and requires
+ * it to be updated in the view.
+ */
+ var arrowDirection: ArrowDirection by
+ Delegates.observable(ArrowDirection.UP) { _, _, _ -> requestPathUpdate() }
+
+ /**
+ * Arrow position along the X axis and its direction. The position is adjusted to the content
+ * corner radius when applied so it doesn't go into rounded corner area
+ */
+ var arrowPosition: ArrowPosition by
+ Delegates.observable(ArrowPosition.Center) { _, _, _ -> requestPathUpdate() }
+
+ private val path = Path()
+ private val paint = Paint()
+ private var shouldUpdatePath = true
+
+ init {
+ paint.color = config.color
+ paint.style = Paint.Style.FILL
+ paint.isAntiAlias = true
+ }
+
+ override fun draw(canvas: Canvas) {
+ updatePathIfNeeded()
+ canvas.drawPath(path, paint)
+ }
+
+ override fun onBoundsChange(bounds: Rect?) {
+ requestPathUpdate()
+ }
+
+ /** Should be applied to the view padding if arrow direction changes */
+ override fun getPadding(padding: Rect): Boolean {
+ padding.set(
+ config.contentPadding,
+ config.contentPadding,
+ config.contentPadding,
+ config.contentPadding
+ )
+ when (arrowDirection) {
+ ArrowDirection.UP -> padding.top += config.arrowHeight.toInt()
+ ArrowDirection.DOWN -> padding.bottom += config.arrowHeight.toInt()
+ }
+ return true
+ }
+
+ override fun getOutline(outline: Outline) {
+ updatePathIfNeeded()
+ outline.setPath(path)
+ }
+
+ override fun getOpacity(): Int {
+ return paint.alpha
+ }
+
+ override fun setAlpha(alpha: Int) {
+ paint.alpha = alpha
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ paint.colorFilter = colorFilter
+ }
+
+ /** Schedules path update for the next redraw */
+ private fun requestPathUpdate() {
+ shouldUpdatePath = true
+ }
+
+ /** Updates the path if required, when bounds or arrow direction/position changes */
+ private fun updatePathIfNeeded() {
+ if (shouldUpdatePath) {
+ updatePath()
+ shouldUpdatePath = false
+ }
+ }
+
+ /** Updates the path value using the current bounds, config, arrow direction and position */
+ private fun updatePath() {
+ if (bounds.isEmpty) return
+ // Reset the path state
+ path.reset()
+ // The content rect where the filled rounded rect will be drawn
+ val contentRect = RectF(bounds)
+ when (arrowDirection) {
+ ArrowDirection.UP -> {
+ // Add rounded arrow pointing up to the path
+ addRoundedArrowPositioned(path, arrowPosition)
+ // Inset content rect by the arrow size from the top
+ contentRect.top += config.arrowHeight
+ }
+ ArrowDirection.DOWN -> {
+ val matrix = Matrix()
+ // Flip the path with the matrix to draw arrow pointing down
+ matrix.setScale(1f, -1f, bounds.width() / 2f, bounds.height() / 2f)
+ path.transform(matrix)
+ // Add rounded arrow with the flipped matrix applied, will point down
+ addRoundedArrowPositioned(path, arrowPosition)
+ // Restore the path matrix to the original state with inverted matrix
+ matrix.invert(matrix)
+ path.transform(matrix)
+ // Inset content rect by the arrow size from the bottom
+ contentRect.bottom -= config.arrowHeight
+ }
+ }
+ // Add the content area rounded rect
+ path.addRoundRect(contentRect, config.cornerRadius, config.cornerRadius, Path.Direction.CW)
+ }
+
+ /** Add a rounded arrow pointing up in the horizontal position on the canvas */
+ private fun addRoundedArrowPositioned(path: Path, position: ArrowPosition) {
+ val matrix = Matrix()
+ var translationX = positionValue(position) - config.arrowWidth / 2
+ // Offset to position between rounded corners of the content view
+ translationX = translationX.coerceIn(config.cornerRadius,
+ bounds.width() - config.cornerRadius - config.arrowWidth)
+ // Translate to add the arrow in the center horizontally
+ matrix.setTranslate(-translationX, 0f)
+ path.transform(matrix)
+ // Add rounded arrow
+ addRoundedArrow(path)
+ // Restore the path matrix to the original state with inverted matrix
+ matrix.invert(matrix)
+ path.transform(matrix)
+ }
+
+ /** Adds a rounded arrow pointing up to the path, can be flipped if needed */
+ private fun addRoundedArrow(path: Path) {
+ // Theta is half of the angle inside the triangle tip
+ val thetaTan = config.arrowWidth / (config.arrowHeight * 2f)
+ val theta = atan(thetaTan)
+ val thetaDeg = Math.toDegrees(theta.toDouble()).toFloat()
+ // The center Y value of the circle for the triangle tip
+ val tipCircleCenterY = config.arrowRadius / sin(theta)
+ // The length from triangle tip to intersection point with the circle
+ val tipIntersectionSideLength = config.arrowRadius / thetaTan
+ // The offset from the top to the point of intersection
+ val intersectionTopOffset = tipIntersectionSideLength * cos(theta)
+ // The offset from the center to the point of intersection
+ val intersectionCenterOffset = tipIntersectionSideLength * sin(theta)
+ // The center X of the triangle
+ val arrowCenterX = config.arrowWidth / 2f
+
+ // Set initial position in bottom left of the arrow
+ path.moveTo(0f, config.arrowHeight)
+ // Add the left side of the triangle
+ path.lineTo(arrowCenterX - intersectionCenterOffset, intersectionTopOffset)
+ // Add the arc from the left to the right side of the triangle
+ path.arcTo(
+ /* left = */ arrowCenterX - config.arrowRadius,
+ /* top = */ tipCircleCenterY - config.arrowRadius,
+ /* right = */ arrowCenterX + config.arrowRadius,
+ /* bottom = */ tipCircleCenterY + config.arrowRadius,
+ /* startAngle = */ 180 + thetaDeg,
+ /* sweepAngle = */ 180 - (2 * thetaDeg),
+ /* forceMoveTo = */ false
+ )
+ // Add the right side of the triangle
+ path.lineTo(config.arrowWidth, config.arrowHeight)
+ // Close the path
+ path.close()
+ }
+
+ /** The value of the arrow position provided the position and current bounds */
+ private fun positionValue(position: ArrowPosition): Float {
+ return when (position) {
+ is ArrowPosition.Start -> 0f
+ is ArrowPosition.Center -> bounds.width().toFloat() / 2f
+ is ArrowPosition.End -> bounds.width().toFloat()
+ is ArrowPosition.Custom -> position.value
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt
new file mode 100644
index 000000000000..f8a4946bb5c5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.common.bubbles
+
+import android.content.Context
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.widget.LinearLayout
+
+/** A popup container view that uses [BubblePopupDrawable] as a background */
+open class BubblePopupView
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+ private var popupDrawable: BubblePopupDrawable? = null
+
+ /**
+ * Sets up the popup drawable with the config provided. Required to remove dependency on local
+ * resources
+ */
+ fun setupBackground(config: BubblePopupDrawable.Config) {
+ popupDrawable = BubblePopupDrawable(config)
+ background = popupDrawable
+ forceLayout()
+ }
+
+ /**
+ * Sets the arrow direction for the background drawable and updates the padding to fit the
+ * content inside of the popup drawable
+ */
+ fun setArrowDirection(direction: BubblePopupDrawable.ArrowDirection) {
+ popupDrawable?.let {
+ it.arrowDirection = direction
+ val padding = Rect()
+ if (it.getPadding(padding)) {
+ setPadding(padding.left, padding.top, padding.right, padding.bottom)
+ }
+ }
+ }
+
+ /** Sets the arrow position for the background drawable and triggers redraw */
+ fun setArrowPosition(position: BubblePopupDrawable.ArrowPosition) {
+ popupDrawable?.let {
+ it.arrowPosition = position
+ invalidate()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMediaController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMediaController.kt
new file mode 100644
index 000000000000..2719cd29009e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMediaController.kt
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.common.pip
+
+import android.annotation.DrawableRes
+import android.annotation.StringRes
+import android.app.PendingIntent
+import android.app.RemoteAction
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.graphics.drawable.Icon
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.media.session.MediaSessionManager
+import android.media.session.PlaybackState
+import android.os.Handler
+import android.os.HandlerExecutor
+import android.os.UserHandle
+import com.android.wm.shell.R
+import com.android.wm.shell.pip.PipUtils
+import java.util.function.Consumer
+
+/**
+ * Interfaces with the [MediaSessionManager] to compose the right set of actions to show (only
+ * if there are no actions from the PiP activity itself). The active media controller is only set
+ * when there is a media session from the top PiP activity.
+ */
+class PipMediaController(private val mContext: Context, private val mMainHandler: Handler) {
+ /**
+ * A listener interface to receive notification on changes to the media actions.
+ */
+ interface ActionListener {
+ /**
+ * Called when the media actions changed.
+ */
+ fun onMediaActionsChanged(actions: List<RemoteAction?>?)
+ }
+
+ /**
+ * A listener interface to receive notification on changes to the media metadata.
+ */
+ interface MetadataListener {
+ /**
+ * Called when the media metadata changed.
+ */
+ fun onMediaMetadataChanged(metadata: MediaMetadata?)
+ }
+
+ /**
+ * A listener interface to receive notification on changes to the media session token.
+ */
+ interface TokenListener {
+ /**
+ * Called when the media session token changed.
+ */
+ fun onMediaSessionTokenChanged(token: MediaSession.Token?)
+ }
+
+ private val mHandlerExecutor: HandlerExecutor = HandlerExecutor(mMainHandler)
+ private val mMediaSessionManager: MediaSessionManager?
+ private var mMediaController: MediaController? = null
+ private val mPauseAction: RemoteAction
+ private val mPlayAction: RemoteAction
+ private val mNextAction: RemoteAction
+ private val mPrevAction: RemoteAction
+ private val mMediaActionReceiver: BroadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (mMediaController == null) {
+ // no active media session, bail early.
+ return
+ }
+ when (intent.action) {
+ ACTION_PLAY -> mMediaController!!.transportControls.play()
+ ACTION_PAUSE -> mMediaController!!.transportControls.pause()
+ ACTION_NEXT -> mMediaController!!.transportControls.skipToNext()
+ ACTION_PREV -> mMediaController!!.transportControls.skipToPrevious()
+ }
+ }
+ }
+ private val mPlaybackChangedListener: MediaController.Callback =
+ object : MediaController.Callback() {
+ override fun onPlaybackStateChanged(state: PlaybackState?) {
+ notifyActionsChanged()
+ }
+
+ override fun onMetadataChanged(metadata: MediaMetadata?) {
+ notifyMetadataChanged(metadata)
+ }
+ }
+ private val mSessionsChangedListener =
+ MediaSessionManager.OnActiveSessionsChangedListener { controllers: List<MediaController>? ->
+ resolveActiveMediaController(controllers)
+ }
+ private val mActionListeners = ArrayList<ActionListener>()
+ private val mMetadataListeners = ArrayList<MetadataListener>()
+ private val mTokenListeners = ArrayList<TokenListener>()
+
+ init {
+ val mediaControlFilter = IntentFilter()
+ mediaControlFilter.addAction(ACTION_PLAY)
+ mediaControlFilter.addAction(ACTION_PAUSE)
+ mediaControlFilter.addAction(ACTION_NEXT)
+ mediaControlFilter.addAction(ACTION_PREV)
+ mContext.registerReceiverForAllUsers(
+ mMediaActionReceiver, mediaControlFilter,
+ SYSTEMUI_PERMISSION, mMainHandler, Context.RECEIVER_EXPORTED
+ )
+
+ // Creates the standard media buttons that we may show.
+ mPauseAction = getDefaultRemoteAction(
+ R.string.pip_pause,
+ R.drawable.pip_ic_pause_white, ACTION_PAUSE
+ )
+ mPlayAction = getDefaultRemoteAction(
+ R.string.pip_play,
+ R.drawable.pip_ic_play_arrow_white, ACTION_PLAY
+ )
+ mNextAction = getDefaultRemoteAction(
+ R.string.pip_skip_to_next,
+ R.drawable.pip_ic_skip_next_white, ACTION_NEXT
+ )
+ mPrevAction = getDefaultRemoteAction(
+ R.string.pip_skip_to_prev,
+ R.drawable.pip_ic_skip_previous_white, ACTION_PREV
+ )
+ mMediaSessionManager = mContext.getSystemService(
+ MediaSessionManager::class.java
+ )
+ }
+
+ /**
+ * Handles when an activity is pinned.
+ */
+ fun onActivityPinned() {
+ // Once we enter PiP, try to find the active media controller for the top most activity
+ resolveActiveMediaController(
+ mMediaSessionManager!!.getActiveSessionsForUser(
+ null,
+ UserHandle.CURRENT
+ )
+ )
+ }
+
+ /**
+ * Adds a new media action listener.
+ */
+ fun addActionListener(listener: ActionListener) {
+ if (!mActionListeners.contains(listener)) {
+ mActionListeners.add(listener)
+ listener.onMediaActionsChanged(mediaActions)
+ }
+ }
+
+ /**
+ * Removes a media action listener.
+ */
+ fun removeActionListener(listener: ActionListener) {
+ listener.onMediaActionsChanged(emptyList<RemoteAction>())
+ mActionListeners.remove(listener)
+ }
+
+ /**
+ * Adds a new media metadata listener.
+ */
+ fun addMetadataListener(listener: MetadataListener) {
+ if (!mMetadataListeners.contains(listener)) {
+ mMetadataListeners.add(listener)
+ listener.onMediaMetadataChanged(mediaMetadata)
+ }
+ }
+
+ /**
+ * Removes a media metadata listener.
+ */
+ fun removeMetadataListener(listener: MetadataListener) {
+ listener.onMediaMetadataChanged(null)
+ mMetadataListeners.remove(listener)
+ }
+
+ /**
+ * Adds a new token listener.
+ */
+ fun addTokenListener(listener: TokenListener) {
+ if (!mTokenListeners.contains(listener)) {
+ mTokenListeners.add(listener)
+ listener.onMediaSessionTokenChanged(token)
+ }
+ }
+
+ /**
+ * Removes a token listener.
+ */
+ fun removeTokenListener(listener: TokenListener) {
+ listener.onMediaSessionTokenChanged(null)
+ mTokenListeners.remove(listener)
+ }
+
+ private val token: MediaSession.Token?
+ get() = if (mMediaController == null) {
+ null
+ } else mMediaController!!.sessionToken
+ private val mediaMetadata: MediaMetadata?
+ get() = if (mMediaController != null) mMediaController!!.metadata else null
+
+ private val mediaActions: List<RemoteAction?>
+ /**
+ * Gets the set of media actions currently available.
+ */
+ get() {
+ if (mMediaController == null) {
+ return emptyList<RemoteAction>()
+ }
+ // Cache the PlaybackState since it's a Binder call.
+ // Safe because mMediaController is guaranteed non-null here.
+ val playbackState: PlaybackState = mMediaController!!.playbackState
+ ?: return emptyList<RemoteAction>()
+ val mediaActions = ArrayList<RemoteAction?>()
+ val isPlaying = playbackState.isActive
+ val actions = playbackState.actions
+
+ // Prev action
+ mPrevAction.isEnabled =
+ actions and PlaybackState.ACTION_SKIP_TO_PREVIOUS != 0L
+ mediaActions.add(mPrevAction)
+
+ // Play/pause action
+ if (!isPlaying && actions and PlaybackState.ACTION_PLAY != 0L) {
+ mediaActions.add(mPlayAction)
+ } else if (isPlaying && actions and PlaybackState.ACTION_PAUSE != 0L) {
+ mediaActions.add(mPauseAction)
+ }
+
+ // Next action
+ mNextAction.isEnabled =
+ actions and PlaybackState.ACTION_SKIP_TO_NEXT != 0L
+ mediaActions.add(mNextAction)
+ return mediaActions
+ }
+
+ /** @return Default [RemoteAction] sends broadcast back to SysUI.
+ */
+ private fun getDefaultRemoteAction(
+ @StringRes titleAndDescription: Int,
+ @DrawableRes icon: Int,
+ action: String
+ ): RemoteAction {
+ val titleAndDescriptionStr = mContext.getString(titleAndDescription)
+ val intent = Intent(action)
+ intent.setPackage(mContext.packageName)
+ return RemoteAction(
+ Icon.createWithResource(mContext, icon),
+ titleAndDescriptionStr, titleAndDescriptionStr,
+ PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ }
+
+ /**
+ * Re-registers the session listener for the current user.
+ */
+ fun registerSessionListenerForCurrentUser() {
+ mMediaSessionManager!!.removeOnActiveSessionsChangedListener(mSessionsChangedListener)
+ mMediaSessionManager.addOnActiveSessionsChangedListener(
+ null, UserHandle.CURRENT,
+ mHandlerExecutor, mSessionsChangedListener
+ )
+ }
+
+ /**
+ * Tries to find and set the active media controller for the top PiP activity.
+ */
+ private fun resolveActiveMediaController(controllers: List<MediaController>?) {
+ if (controllers != null) {
+ val topActivity = PipUtils.getTopPipActivity(mContext).first
+ if (topActivity != null) {
+ for (i in controllers.indices) {
+ val controller = controllers[i]
+ if (controller.packageName == topActivity.packageName) {
+ setActiveMediaController(controller)
+ return
+ }
+ }
+ }
+ }
+ setActiveMediaController(null)
+ }
+
+ /**
+ * Sets the active media controller for the top PiP activity.
+ */
+ private fun setActiveMediaController(controller: MediaController?) {
+ if (controller != mMediaController) {
+ if (mMediaController != null) {
+ mMediaController!!.unregisterCallback(mPlaybackChangedListener)
+ }
+ mMediaController = controller
+ controller?.registerCallback(mPlaybackChangedListener, mMainHandler)
+ notifyActionsChanged()
+ notifyMetadataChanged(mediaMetadata)
+ notifyTokenChanged(token)
+
+ // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV)
+ }
+ }
+
+ /**
+ * Notifies all listeners that the actions have changed.
+ */
+ private fun notifyActionsChanged() {
+ if (mActionListeners.isNotEmpty()) {
+ val actions = mediaActions
+ mActionListeners.forEach(
+ Consumer { l: ActionListener -> l.onMediaActionsChanged(actions) })
+ }
+ }
+
+ /**
+ * Notifies all listeners that the metadata have changed.
+ */
+ private fun notifyMetadataChanged(metadata: MediaMetadata?) {
+ if (mMetadataListeners.isNotEmpty()) {
+ mMetadataListeners.forEach(Consumer { l: MetadataListener ->
+ l.onMediaMetadataChanged(
+ metadata
+ )
+ })
+ }
+ }
+
+ private fun notifyTokenChanged(token: MediaSession.Token?) {
+ if (mTokenListeners.isNotEmpty()) {
+ mTokenListeners.forEach(Consumer { l: TokenListener ->
+ l.onMediaSessionTokenChanged(
+ token
+ )
+ })
+ }
+ }
+
+ companion object {
+ private const val SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF"
+ private const val ACTION_PLAY = "com.android.wm.shell.pip.PLAY"
+ private const val ACTION_PAUSE = "com.android.wm.shell.pip.PAUSE"
+ private const val ACTION_NEXT = "com.android.wm.shell.pip.NEXT"
+ private const val ACTION_PREV = "com.android.wm.shell.pip.PREV"
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt
index 3e5a19b69a59..642dacc425d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,68 +13,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.wm.shell.common.pip
-package com.android.wm.shell.pip;
-
-import android.app.TaskInfo;
-import android.content.pm.PackageManager;
-
-import com.android.internal.logging.UiEvent;
-import com.android.internal.logging.UiEventLogger;
+import android.app.TaskInfo
+import android.content.pm.PackageManager
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
/**
* Helper class that ends PiP log to UiEvent, see also go/uievent
*/
-public class PipUiEventLogger {
-
- private static final int INVALID_PACKAGE_UID = -1;
-
- private final UiEventLogger mUiEventLogger;
- private final PackageManager mPackageManager;
-
- private String mPackageName;
- private int mPackageUid = INVALID_PACKAGE_UID;
-
- public PipUiEventLogger(UiEventLogger uiEventLogger, PackageManager packageManager) {
- mUiEventLogger = uiEventLogger;
- mPackageManager = packageManager;
- }
-
- public void setTaskInfo(TaskInfo taskInfo) {
- if (taskInfo != null && taskInfo.topActivity != null) {
- mPackageName = taskInfo.topActivity.getPackageName();
- mPackageUid = getUid(mPackageName, taskInfo.userId);
+class PipUiEventLogger(
+ private val mUiEventLogger: UiEventLogger,
+ private val mPackageManager: PackageManager
+) {
+ private var mPackageName: String? = null
+ private var mPackageUid = INVALID_PACKAGE_UID
+ fun setTaskInfo(taskInfo: TaskInfo?) {
+ if (taskInfo?.topActivity != null) {
+ // safe because topActivity is guaranteed non-null here
+ mPackageName = taskInfo.topActivity!!.packageName
+ mPackageUid = getUid(mPackageName!!, taskInfo.userId)
} else {
- mPackageName = null;
- mPackageUid = INVALID_PACKAGE_UID;
+ mPackageName = null
+ mPackageUid = INVALID_PACKAGE_UID
}
}
/**
* Sends log via UiEvent, reference go/uievent for how to debug locally
*/
- public void log(PipUiEventEnum event) {
+ fun log(event: PipUiEventEnum?) {
if (mPackageName == null || mPackageUid == INVALID_PACKAGE_UID) {
- return;
+ return
}
- mUiEventLogger.log(event, mPackageUid, mPackageName);
+ mUiEventLogger.log(event!!, mPackageUid, mPackageName)
}
- private int getUid(String packageName, int userId) {
- int uid = INVALID_PACKAGE_UID;
+ private fun getUid(packageName: String, userId: Int): Int {
+ var uid = INVALID_PACKAGE_UID
try {
uid = mPackageManager.getApplicationInfoAsUser(
- packageName, 0 /* ApplicationInfoFlags */, userId).uid;
- } catch (PackageManager.NameNotFoundException e) {
+ packageName, 0 /* ApplicationInfoFlags */, userId
+ ).uid
+ } catch (e: PackageManager.NameNotFoundException) {
// do nothing.
}
- return uid;
+ return uid
}
/**
* Enums for logging the PiP events to UiEvent
*/
- public enum PipUiEventEnum implements UiEventLogger.UiEventEnum {
+ enum class PipUiEventEnum(private val mId: Int) : UiEventLogger.UiEventEnum {
@UiEvent(doc = "Activity enters picture-in-picture mode")
PICTURE_IN_PICTURE_ENTER(603),
@@ -99,8 +90,10 @@ public class PipUiEventLogger {
@UiEvent(doc = "Hides picture-in-picture menu")
PICTURE_IN_PICTURE_HIDE_MENU(608),
- @UiEvent(doc = "Changes the aspect ratio of picture-in-picture window. This is inherited"
- + " from previous Tron-based logging and currently not in use.")
+ @UiEvent(
+ doc = "Changes the aspect ratio of picture-in-picture window. This is inherited" +
+ " from previous Tron-based logging and currently not in use."
+ )
PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
@UiEvent(doc = "User resize of the picture-in-picture window")
@@ -121,15 +114,12 @@ public class PipUiEventLogger {
@UiEvent(doc = "Closes PiP with app-provided close action")
PICTURE_IN_PICTURE_CUSTOM_CLOSE(1058);
- private final int mId;
-
- PipUiEventEnum(int id) {
- mId = id;
+ override fun getId(): Int {
+ return mId
}
+ }
- @Override
- public int getId() {
- return mId;
- }
+ companion object {
+ private const val INVALID_PACKAGE_UID = -1
}
-}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 54f89846ac85..7bf0893c60c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -230,8 +230,10 @@ public class CompatUIController implements OnDisplaysChangedListener,
// The user aspect ratio button should not be handled when a new TaskInfo is
// sent because of a double tap or when in multi-window mode.
if (taskInfo.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
- mUserAspectRatioSettingsLayout.release();
- mUserAspectRatioSettingsLayout = null;
+ if (mUserAspectRatioSettingsLayout != null) {
+ mUserAspectRatioSettingsLayout.release();
+ mUserAspectRatioSettingsLayout = null;
+ }
return;
}
if (!taskInfo.isFromLetterboxDoubleTap) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index c06b22cdb8a4..94723416cdf8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -20,6 +20,7 @@ import static com.android.wm.shell.onehanded.OneHandedController.SUPPORT_ONE_HAN
import android.app.ActivityTaskManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.SystemProperties;
import android.view.IWindowManager;
@@ -57,6 +58,8 @@ import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.compatui.CompatUIConfiguration;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.compatui.CompatUIShellCommandHandler;
@@ -331,6 +334,25 @@ public abstract class WMShellBaseModule {
abstract ShellBackAnimationRegistry optionalBackAnimationRegistry();
//
+ // PiP (optional feature)
+ //
+
+ @WMSingleton
+ @Provides
+ static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
+ PackageManager packageManager) {
+ return new PipUiEventLogger(uiEventLogger, packageManager);
+ }
+
+ @WMSingleton
+ @Provides
+ static PipMediaController providePipMediaController(Context context,
+ @ShellMainThread Handler mainHandler) {
+ return new PipMediaController(context, mainHandler);
+ }
+
+
+ //
// Bubbles (optional feature)
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index 9bf973f523bf..24ef44a7c0f4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -32,6 +32,8 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
@@ -41,7 +43,6 @@ import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
@@ -49,7 +50,6 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransition;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
index e8fae2490bc5..c4ca5013afb6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
@@ -17,15 +17,9 @@
package com.android.wm.shell.dagger.pip;
import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Handler;
-import com.android.internal.logging.UiEventLogger;
-import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.dagger.WMSingleton;
-import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipUiEventLogger;
import dagger.Module;
import dagger.Provides;
@@ -36,24 +30,9 @@ import dagger.Provides;
*/
@Module
public abstract class Pip1SharedModule {
- // Needs handler for registering broadcast receivers
- @WMSingleton
- @Provides
- static PipMediaController providePipMediaController(Context context,
- @ShellMainThread Handler mainHandler) {
- return new PipMediaController(context, mainHandler);
- }
-
@WMSingleton
@Provides
static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
return new PipSurfaceTransactionHelper(context);
}
-
- @WMSingleton
- @Provides
- static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
- PackageManager packageManager) {
- return new PipUiEventLogger(uiEventLogger, packageManager);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index c7c6e8a14278..8dec4ea542a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.dagger.pip;
import android.annotation.Nullable;
+import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.pip2.PipTransition;
@@ -26,9 +27,9 @@ import dagger.Provides;
/**
* Provides dependencies from {@link com.android.wm.shell.pip2}, this implementation is meant to be
- * the successor of its sibling {@link Pip1SharedModule}.
+ * the successor of its sibling {@link Pip1Module}.
*/
-@Module
+@Module(includes = WMShellBaseModule.class)
public abstract class Pip2Module {
@WMSingleton
@Provides
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
index 80ffbb0968f3..a6ff9ecf7f4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
@@ -30,20 +30,20 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.pip.LegacySizeSpecSource;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
import com.android.wm.shell.pip.tv.TvPipBoundsController;
import com.android.wm.shell.pip.tv.TvPipBoundsState;
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
deleted file mode 100644
index ddffb5bdacde..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.pip;
-
-import static android.app.PendingIntent.FLAG_IMMUTABLE;
-import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-
-import android.annotation.DrawableRes;
-import android.annotation.StringRes;
-import android.annotation.SuppressLint;
-import android.app.PendingIntent;
-import android.app.RemoteAction;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
-import android.media.session.PlaybackState;
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.UserHandle;
-
-import androidx.annotation.Nullable;
-
-import com.android.wm.shell.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Interfaces with the {@link MediaSessionManager} to compose the right set of actions to show (only
- * if there are no actions from the PiP activity itself). The active media controller is only set
- * when there is a media session from the top PiP activity.
- */
-public class PipMediaController {
- private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";
-
- private static final String ACTION_PLAY = "com.android.wm.shell.pip.PLAY";
- private static final String ACTION_PAUSE = "com.android.wm.shell.pip.PAUSE";
- private static final String ACTION_NEXT = "com.android.wm.shell.pip.NEXT";
- private static final String ACTION_PREV = "com.android.wm.shell.pip.PREV";
-
- /**
- * A listener interface to receive notification on changes to the media actions.
- */
- public interface ActionListener {
- /**
- * Called when the media actions changed.
- */
- void onMediaActionsChanged(List<RemoteAction> actions);
- }
-
- /**
- * A listener interface to receive notification on changes to the media metadata.
- */
- public interface MetadataListener {
- /**
- * Called when the media metadata changed.
- */
- void onMediaMetadataChanged(MediaMetadata metadata);
- }
-
- /**
- * A listener interface to receive notification on changes to the media session token.
- */
- public interface TokenListener {
- /**
- * Called when the media session token changed.
- */
- void onMediaSessionTokenChanged(MediaSession.Token token);
- }
-
- private final Context mContext;
- private final Handler mMainHandler;
- private final HandlerExecutor mHandlerExecutor;
-
- private final MediaSessionManager mMediaSessionManager;
- private MediaController mMediaController;
-
- private RemoteAction mPauseAction;
- private RemoteAction mPlayAction;
- private RemoteAction mNextAction;
- private RemoteAction mPrevAction;
-
- private final BroadcastReceiver mMediaActionReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mMediaController == null || mMediaController.getTransportControls() == null) {
- // no active media session, bail early.
- return;
- }
- switch (intent.getAction()) {
- case ACTION_PLAY:
- mMediaController.getTransportControls().play();
- break;
- case ACTION_PAUSE:
- mMediaController.getTransportControls().pause();
- break;
- case ACTION_NEXT:
- mMediaController.getTransportControls().skipToNext();
- break;
- case ACTION_PREV:
- mMediaController.getTransportControls().skipToPrevious();
- break;
- }
- }
- };
-
- private final MediaController.Callback mPlaybackChangedListener =
- new MediaController.Callback() {
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- notifyActionsChanged();
- }
-
- @Override
- public void onMetadataChanged(@Nullable MediaMetadata metadata) {
- notifyMetadataChanged(metadata);
- }
- };
-
- private final MediaSessionManager.OnActiveSessionsChangedListener mSessionsChangedListener =
- this::resolveActiveMediaController;
-
- private final ArrayList<ActionListener> mActionListeners = new ArrayList<>();
- private final ArrayList<MetadataListener> mMetadataListeners = new ArrayList<>();
- private final ArrayList<TokenListener> mTokenListeners = new ArrayList<>();
-
- public PipMediaController(Context context, Handler mainHandler) {
- mContext = context;
- mMainHandler = mainHandler;
- mHandlerExecutor = new HandlerExecutor(mMainHandler);
- if (!PipUtils.isPip2ExperimentEnabled()) {
- IntentFilter mediaControlFilter = new IntentFilter();
- mediaControlFilter.addAction(ACTION_PLAY);
- mediaControlFilter.addAction(ACTION_PAUSE);
- mediaControlFilter.addAction(ACTION_NEXT);
- mediaControlFilter.addAction(ACTION_PREV);
- mContext.registerReceiverForAllUsers(mMediaActionReceiver, mediaControlFilter,
- SYSTEMUI_PERMISSION, mainHandler, Context.RECEIVER_EXPORTED);
- }
-
- // Creates the standard media buttons that we may show.
- mPauseAction = getDefaultRemoteAction(R.string.pip_pause,
- R.drawable.pip_ic_pause_white, ACTION_PAUSE);
- mPlayAction = getDefaultRemoteAction(R.string.pip_play,
- R.drawable.pip_ic_play_arrow_white, ACTION_PLAY);
- mNextAction = getDefaultRemoteAction(R.string.pip_skip_to_next,
- R.drawable.pip_ic_skip_next_white, ACTION_NEXT);
- mPrevAction = getDefaultRemoteAction(R.string.pip_skip_to_prev,
- R.drawable.pip_ic_skip_previous_white, ACTION_PREV);
-
- mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
- }
-
- /**
- * Handles when an activity is pinned.
- */
- public void onActivityPinned() {
- // Once we enter PiP, try to find the active media controller for the top most activity
- resolveActiveMediaController(mMediaSessionManager.getActiveSessionsForUser(null,
- UserHandle.CURRENT));
- }
-
- /**
- * Adds a new media action listener.
- */
- public void addActionListener(ActionListener listener) {
- if (!mActionListeners.contains(listener)) {
- mActionListeners.add(listener);
- listener.onMediaActionsChanged(getMediaActions());
- }
- }
-
- /**
- * Removes a media action listener.
- */
- public void removeActionListener(ActionListener listener) {
- listener.onMediaActionsChanged(Collections.emptyList());
- mActionListeners.remove(listener);
- }
-
- /**
- * Adds a new media metadata listener.
- */
- public void addMetadataListener(MetadataListener listener) {
- if (!mMetadataListeners.contains(listener)) {
- mMetadataListeners.add(listener);
- listener.onMediaMetadataChanged(getMediaMetadata());
- }
- }
-
- /**
- * Removes a media metadata listener.
- */
- public void removeMetadataListener(MetadataListener listener) {
- listener.onMediaMetadataChanged(null);
- mMetadataListeners.remove(listener);
- }
-
- /**
- * Adds a new token listener.
- */
- public void addTokenListener(TokenListener listener) {
- if (!mTokenListeners.contains(listener)) {
- mTokenListeners.add(listener);
- listener.onMediaSessionTokenChanged(getToken());
- }
- }
-
- /**
- * Removes a token listener.
- */
- public void removeTokenListener(TokenListener listener) {
- listener.onMediaSessionTokenChanged(null);
- mTokenListeners.remove(listener);
- }
-
- private MediaSession.Token getToken() {
- if (mMediaController == null) {
- return null;
- }
- return mMediaController.getSessionToken();
- }
-
- private MediaMetadata getMediaMetadata() {
- return mMediaController != null ? mMediaController.getMetadata() : null;
- }
-
- /**
- * Gets the set of media actions currently available.
- */
- // This is due to using PlaybackState#isActive, which is added in API 31.
- // It can be removed when min_sdk of the app is set to 31 or greater.
- @SuppressLint("NewApi")
- private List<RemoteAction> getMediaActions() {
- // Cache the PlaybackState since it's a Binder call.
- final PlaybackState playbackState;
- if (mMediaController == null
- || (playbackState = mMediaController.getPlaybackState()) == null) {
- return Collections.emptyList();
- }
-
- ArrayList<RemoteAction> mediaActions = new ArrayList<>();
- boolean isPlaying = playbackState.isActive();
- long actions = playbackState.getActions();
-
- // Prev action
- mPrevAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0);
- mediaActions.add(mPrevAction);
-
- // Play/pause action
- if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) {
- mediaActions.add(mPlayAction);
- } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) {
- mediaActions.add(mPauseAction);
- }
-
- // Next action
- mNextAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0);
- mediaActions.add(mNextAction);
- return mediaActions;
- }
-
- /** @return Default {@link RemoteAction} sends broadcast back to SysUI. */
- private RemoteAction getDefaultRemoteAction(@StringRes int titleAndDescription,
- @DrawableRes int icon, String action) {
- final String titleAndDescriptionStr = mContext.getString(titleAndDescription);
- final Intent intent = new Intent(action);
- intent.setPackage(mContext.getPackageName());
- return new RemoteAction(Icon.createWithResource(mContext, icon),
- titleAndDescriptionStr, titleAndDescriptionStr,
- PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
- FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
- }
-
- /**
- * Re-registers the session listener for the current user.
- */
- public void registerSessionListenerForCurrentUser() {
- mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionsChangedListener);
- mMediaSessionManager.addOnActiveSessionsChangedListener(null, UserHandle.CURRENT,
- mHandlerExecutor, mSessionsChangedListener);
- }
-
- /**
- * Tries to find and set the active media controller for the top PiP activity.
- */
- private void resolveActiveMediaController(List<MediaController> controllers) {
- if (controllers != null) {
- final ComponentName topActivity = PipUtils.getTopPipActivity(mContext).first;
- if (topActivity != null) {
- for (int i = 0; i < controllers.size(); i++) {
- final MediaController controller = controllers.get(i);
- if (controller.getPackageName().equals(topActivity.getPackageName())) {
- setActiveMediaController(controller);
- return;
- }
- }
- }
- }
- setActiveMediaController(null);
- }
-
- /**
- * Sets the active media controller for the top PiP activity.
- */
- private void setActiveMediaController(MediaController controller) {
- if (controller != mMediaController) {
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mPlaybackChangedListener);
- }
- mMediaController = controller;
- if (controller != null) {
- controller.registerCallback(mPlaybackChangedListener, mMainHandler);
- }
- notifyActionsChanged();
- notifyMetadataChanged(getMediaMetadata());
- notifyTokenChanged(getToken());
-
- // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV)
- }
- }
-
- /**
- * Notifies all listeners that the actions have changed.
- */
- private void notifyActionsChanged() {
- if (!mActionListeners.isEmpty()) {
- List<RemoteAction> actions = getMediaActions();
- mActionListeners.forEach(l -> l.onMediaActionsChanged(actions));
- }
- }
-
- /**
- * Notifies all listeners that the metadata have changed.
- */
- private void notifyMetadataChanged(MediaMetadata metadata) {
- if (!mMetadataListeners.isEmpty()) {
- mMetadataListeners.forEach(l -> l.onMediaMetadataChanged(metadata));
- }
- }
-
- private void notifyTokenChanged(MediaSession.Token token) {
- if (!mTokenListeners.isEmpty()) {
- mTokenListeners.forEach(l -> l.onMediaSessionTokenChanged(token));
- }
- }
-}
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 19c60c2a9117..296857b196cf 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
@@ -82,6 +82,7 @@ import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 5e1b6becfa45..cc182ba89985 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -38,12 +38,12 @@ import android.view.WindowManagerGlobal;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController.ActionListener;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipMediaController;
-import com.android.wm.shell.pip.PipMediaController.ActionListener;
import com.android.wm.shell.pip.PipMenuController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
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 f25110ac3257..5c65d7839f07 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
@@ -76,6 +76,7 @@ import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.IPip;
@@ -87,7 +88,6 @@ import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipDisplayLayoutState;
import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
-import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index da455f85d908..4e75847b6bc0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -38,7 +38,7 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.bubbles.DismissCircleView;
import com.android.wm.shell.common.bubbles.DismissView;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
-import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import kotlin.Unit;
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 779c539a2097..837426ae3aab 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
@@ -66,7 +66,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index b251f6f55794..8f0a8e11103c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -33,7 +33,6 @@ import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.SystemProperties;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
@@ -48,19 +47,16 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import java.util.function.Consumer;
-
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
+import java.util.function.Consumer;
+
/**
* A helper to animate and manipulate the PiP.
*/
public class PipMotionHelper implements PipAppOpsListener.Callback,
FloatingContentCoordinator.FloatingContent {
-
- public static final boolean ENABLE_FLING_TO_DISMISS_PIP =
- SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_pip", false);
private static final String TAG = "PipMotionHelper";
private static final boolean DEBUG = false;
@@ -707,7 +703,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
loc[1] = animatedPipBounds.top;
}
};
- mMagnetizedPip.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_PIP);
+ mMagnetizedPip.setFlingToTargetEnabled(false);
}
return mMagnetizedPip;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index abe2db094a5c..4e687dda4e77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -46,11 +46,11 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.wm.shell.R;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipUiEventLogger;
import java.io.PrintWriter;
import java.util.function.Consumer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 9f7dee74d06e..6055fd9d9593 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -50,13 +50,13 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
index 11c2665c9665..f1606f6a8ca5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
@@ -35,7 +35,7 @@ import android.content.Context;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
-import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index e3544c63dd6e..5f5d8ad588dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -48,11 +48,11 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index f22ee595e6c9..39c7a4b220a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -36,7 +36,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ImageUtils;
import com.android.wm.shell.R;
-import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
index 4819f665d6d3..dbec607c2ae9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
@@ -25,6 +25,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -35,7 +36,6 @@ import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index f35eda6caef0..ac142e955b83 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -203,6 +203,17 @@ public class RecentTasksController implements TaskStackListenerCallback,
}
}
+ @Nullable
+ public SplitBounds getSplitBoundsForTaskId(int taskId) {
+ if (taskId == INVALID_TASK_ID) {
+ return null;
+ }
+
+ // We could do extra verification of requiring both taskIds of a pair and verifying that
+ // the same split bounds object is returned... but meh. Seems unnecessary.
+ return mTaskSplitBoundsMap.get(taskId);
+ }
+
@Override
public Context getContext() {
return mContext;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index a11d9528a170..dc6dc7910feb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.recents;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -23,6 +24,8 @@ import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_SLEEP;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
+
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
@@ -69,6 +72,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
private final Transitions mTransitions;
private final ShellExecutor mExecutor;
+ @Nullable
+ private final RecentTasksController mRecentTasksController;
private IApplicationThread mAnimApp = null;
private final ArrayList<RecentsController> mControllers = new ArrayList<>();
@@ -82,6 +87,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
@Nullable RecentTasksController recentTasksController) {
mTransitions = transitions;
mExecutor = transitions.getMainExecutor();
+ mRecentTasksController = recentTasksController;
if (!Transitions.ENABLE_SHELL_TRANSITIONS) return;
if (recentTasksController == null) return;
shellInit.addInitCallback(() -> {
@@ -417,6 +423,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
mLeashMap = new ArrayMap<>();
mKeyguardLocked = (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0;
+ int closingSplitTaskId = INVALID_TASK_ID;
final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>();
TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter();
@@ -443,6 +450,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
apps.add(target);
if (TransitionUtil.isClosingType(change.getMode())) {
mPausingTasks.add(new TaskState(change, target.leash));
+ closingSplitTaskId = change.getTaskInfo().taskId;
if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
" adding pausing leaf home taskId=%d", taskInfo.taskId);
@@ -500,13 +508,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
}
t.apply();
+ Bundle b = new Bundle(1 /*capacity*/);
+ b.putParcelable(KEY_EXTRA_SPLIT_BOUNDS,
+ mRecentTasksController.getSplitBoundsForTaskId(closingSplitTaskId));
try {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.start: calling onAnimationStart", mInstanceId);
mListener.onAnimationStart(this,
apps.toArray(new RemoteAnimationTarget[apps.size()]),
wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]),
- new Rect(0, 0, 0, 0), new Rect());
+ new Rect(0, 0, 0, 0), new Rect(), b);
} catch (RemoteException e) {
Slog.e(TAG, "Error starting recents animation", e);
cancel("onAnimationStart() failed");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java
index f209521b1da4..0edcff45f648 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java
@@ -26,6 +26,8 @@ import java.util.Objects;
* tasks/leashes/etc in Launcher
*/
public class SplitBounds implements Parcelable {
+ public static final String KEY_EXTRA_SPLIT_BOUNDS = "key_SplitBounds";
+
public final Rect leftTopBounds;
public final Rect rightBottomBounds;
/** This rect represents the actual gap between the two apps */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index 42be818ee0fb..43e7696ffa93 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.pip
import android.graphics.Rect
-import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
@@ -82,8 +81,8 @@ class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
/**
* Checks that the visible region area of [pipApp] moves to closest edge during the animation.
*/
- @Presubmit
@Test
+ @FlakyTest(bugId = 294993100)
fun pipLayerMovesToClosestEdge() {
flicker.assertLayers {
val pipLayerList = layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
@@ -97,6 +96,90 @@ class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
}
}
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun entireScreenCovered() {
+ super.entireScreenCovered()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun hasAtMostOnePipDismissOverlayWindow() {
+ super.hasAtMostOnePipDismissOverlayWindow()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun navBarLayerIsVisibleAtStartAndEnd() {
+ super.navBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun navBarLayerPositionAtStartAndEnd() {
+ super.navBarLayerPositionAtStartAndEnd()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun navBarWindowIsAlwaysVisible() {
+ super.navBarWindowIsAlwaysVisible()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun statusBarLayerIsVisibleAtStartAndEnd() {
+ super.statusBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun statusBarLayerPositionAtStartAndEnd() {
+ super.statusBarLayerPositionAtStartAndEnd()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun statusBarWindowIsAlwaysVisible() {
+ super.statusBarWindowIsAlwaysVisible()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun taskBarLayerIsVisibleAtStartAndEnd() {
+ super.taskBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ // Overridden to remove @Presubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun taskBarWindowIsAlwaysVisible() {
+ super.taskBarWindowIsAlwaysVisible()
+ }
+
companion object {
/**
* Creates the test configurations.
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 096af39488e9..2008d019d2c4 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
@@ -92,7 +92,7 @@ abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
@Presubmit
@Test
- fun hasAtMostOnePipDismissOverlayWindow() {
+ open fun hasAtMostOnePipDismissOverlayWindow() {
val matcher = ComponentNameMatcher("", "pip-dismiss-overlay")
flicker.assertWm {
val overlaysPerState =
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 1e3fe421140a..248d66590542 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -53,6 +53,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 05c6ba9f0897..911f5e165ef1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -56,12 +56,12 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index 689b5c5a708c..12b4f3e50f32 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -37,6 +37,7 @@ import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -45,7 +46,6 @@ import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index f65d7af70f49..314f195d87ac 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -33,6 +33,7 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -41,7 +42,6 @@ import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.sysui.ShellInit;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
index ec84d7e20714..45f6c8c7f69f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
@@ -38,7 +38,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 2c69522413d5..9e9e1ca341eb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.recents;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -367,6 +368,37 @@ public class RecentTasksControllerTest extends ShellTestCase {
verify(mRecentTasksController).notifyRecentTasksChanged();
}
+ @Test
+ public void getNullSplitBoundsNonSplitTask() {
+ SplitBounds sb = mRecentTasksController.getSplitBoundsForTaskId(3);
+ assertNull("splitBounds should be null for non-split task", sb);
+ }
+
+ @Test
+ public void getNullSplitBoundsInvalidTask() {
+ SplitBounds sb = mRecentTasksController.getSplitBoundsForTaskId(INVALID_TASK_ID);
+ assertNull("splitBounds should be null for invalid taskID", sb);
+ }
+
+ @Test
+ public void getSplitBoundsForSplitTask() {
+ SplitBounds pair1Bounds = mock(SplitBounds.class);
+ SplitBounds pair2Bounds = mock(SplitBounds.class);
+
+ mRecentTasksController.addSplitPair(1, 2, pair1Bounds);
+ mRecentTasksController.addSplitPair(4, 3, pair2Bounds);
+
+ SplitBounds splitBounds2 = mRecentTasksController.getSplitBoundsForTaskId(2);
+ SplitBounds splitBounds1 = mRecentTasksController.getSplitBoundsForTaskId(1);
+ assertEquals("Different splitBounds for same pair", splitBounds1, splitBounds2);
+ assertEquals(splitBounds1, pair1Bounds);
+
+ SplitBounds splitBounds3 = mRecentTasksController.getSplitBoundsForTaskId(3);
+ SplitBounds splitBounds4 = mRecentTasksController.getSplitBoundsForTaskId(4);
+ assertEquals("Different splitBounds for same pair", splitBounds3, splitBounds4);
+ assertEquals(splitBounds4, pair2Bounds);
+ }
+
/**
* Helper to create a task with a given task id.
*/
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 99a1ac663286..a57a7bf4c659 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -99,6 +99,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -1061,7 +1062,8 @@ public class ShellTransitionTests extends ShellTestCase {
mTransactionPool, createTestDisplayController(), mMainExecutor,
mMainHandler, mAnimExecutor);
final RecentsTransitionHandler recentsHandler =
- new RecentsTransitionHandler(shellInit, transitions, null);
+ new RecentsTransitionHandler(shellInit, transitions,
+ mock(RecentTasksController.class));
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
shellInit.init();
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index fb2b57193b83..795bb3c716d1 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -91,7 +91,7 @@ String8 idmapPathForPackagePath(const String8& pkgPath) {
path.appendPath(kResourceCache);
char buf[256]; // 256 chars should be enough for anyone...
- strncpy(buf, pkgPath.string(), 255);
+ strncpy(buf, pkgPath.c_str(), 255);
buf[255] = '\0';
char* filename = buf;
while (*filename && *filename == '/') {
@@ -183,15 +183,15 @@ bool AssetManager::addAssetPath(
if (kAppZipName) {
realPath.appendPath(kAppZipName);
}
- ap.type = ::getFileType(realPath.string());
+ ap.type = ::getFileType(realPath.c_str());
if (ap.type == kFileTypeRegular) {
ap.path = realPath;
} else {
ap.path = path;
- ap.type = ::getFileType(path.string());
+ ap.type = ::getFileType(path.c_str());
if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
ALOGW("Asset path %s is neither a directory nor file (type=%d).",
- path.string(), (int)ap.type);
+ path.c_str(), (int)ap.type);
return false;
}
}
@@ -207,7 +207,7 @@ bool AssetManager::addAssetPath(
}
ALOGV("In %p Asset %s path: %s", this,
- ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
+ ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.c_str());
ap.isSystemAsset = isSystemAsset;
ssize_t apPos = mAssetPaths.add(ap);
@@ -248,7 +248,7 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
Asset* idmap = NULL;
if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) {
- ALOGW("failed to open idmap file %s\n", idmapPath.string());
+ ALOGW("failed to open idmap file %s\n", idmapPath.c_str());
return false;
}
@@ -256,7 +256,7 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
String8 overlayPath;
if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(),
NULL, NULL, NULL, &targetPath, &overlayPath)) {
- ALOGW("failed to read idmap file %s\n", idmapPath.string());
+ ALOGW("failed to read idmap file %s\n", idmapPath.c_str());
delete idmap;
return false;
}
@@ -264,29 +264,29 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
if (overlayPath != packagePath) {
ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n",
- idmapPath.string(), packagePath.string(), overlayPath.string());
+ idmapPath.c_str(), packagePath.c_str(), overlayPath.c_str());
return false;
}
- if (access(targetPath.string(), R_OK) != 0) {
- ALOGW("failed to access file %s: %s\n", targetPath.string(), strerror(errno));
+ if (access(targetPath.c_str(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", targetPath.c_str(), strerror(errno));
return false;
}
- if (access(idmapPath.string(), R_OK) != 0) {
- ALOGW("failed to access file %s: %s\n", idmapPath.string(), strerror(errno));
+ if (access(idmapPath.c_str(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", idmapPath.c_str(), strerror(errno));
return false;
}
- if (access(overlayPath.string(), R_OK) != 0) {
- ALOGW("failed to access file %s: %s\n", overlayPath.string(), strerror(errno));
+ if (access(overlayPath.c_str(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", overlayPath.c_str(), strerror(errno));
return false;
}
asset_path oap;
oap.path = overlayPath;
- oap.type = ::getFileType(overlayPath.string());
+ oap.type = ::getFileType(overlayPath.c_str());
oap.idmap = idmapPath;
#if 0
ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n",
- targetPath.string(), overlayPath.string(), idmapPath.string());
+ targetPath.c_str(), overlayPath.c_str(), idmapPath.c_str());
#endif
mAssetPaths.add(oap);
*cookie = static_cast<int32_t>(mAssetPaths.size());
@@ -310,7 +310,7 @@ bool AssetManager::addAssetFd(
ap.type = kFileTypeRegular;
ap.assumeOwnership = assume_ownership;
- ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.string());
+ ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.c_str());
ssize_t apPos = mAssetPaths.add(ap);
@@ -343,11 +343,11 @@ bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApk
assets[i] = openNonAssetInPathLocked("resources.arsc",
Asset::ACCESS_BUFFER, ap);
if (assets[i] == NULL) {
- ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
+ ALOGW("failed to find resources.arsc in %s\n", ap.path.c_str());
goto exit;
}
if (tables[i].add(assets[i]) != NO_ERROR) {
- ALOGW("failed to add %s to resource table", paths[i].string());
+ ALOGW("failed to add %s to resource table", paths[i].c_str());
goto exit;
}
}
@@ -449,8 +449,8 @@ Asset* AssetManager::open(const char* fileName, AccessMode mode)
while (i > 0) {
i--;
ALOGV("Looking for asset '%s' in '%s'\n",
- assetName.string(), mAssetPaths.itemAt(i).path.string());
- Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode,
+ assetName.c_str(), mAssetPaths.itemAt(i).path.c_str());
+ Asset* pAsset = openNonAssetInPathLocked(assetName.c_str(), mode,
mAssetPaths.editItemAt(i));
if (pAsset != NULL) {
return pAsset != kExcludedAsset ? pAsset : NULL;
@@ -478,7 +478,7 @@ Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t
size_t i = mAssetPaths.size();
while (i > 0) {
i--;
- ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string());
+ ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.c_str());
Asset* pAsset = openNonAssetInPathLocked(
fileName, mode, mAssetPaths.editItemAt(i));
if (pAsset != NULL) {
@@ -500,7 +500,7 @@ Asset* AssetManager::openNonAsset(const int32_t cookie, const char* fileName, Ac
if (which < mAssetPaths.size()) {
ALOGV("Looking for non-asset '%s' in '%s'\n", fileName,
- mAssetPaths.itemAt(which).path.string());
+ mAssetPaths.itemAt(which).path.c_str());
Asset* pAsset = openNonAssetInPathLocked(
fileName, mode, mAssetPaths.editItemAt(which));
if (pAsset != NULL) {
@@ -546,10 +546,10 @@ bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const {
ResTable* sharedRes = NULL;
bool shared = true;
bool onlyEmptyResources = true;
- ATRACE_NAME(ap.path.string());
+ ATRACE_NAME(ap.path.c_str());
Asset* idmap = openIdmapLocked(ap);
size_t nextEntryIdx = mResources->getTableCount();
- ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
+ ALOGV("Looking for resource asset in '%s'\n", ap.path.c_str());
if (ap.type != kFileTypeDirectory && ap.rawFd < 0) {
if (nextEntryIdx == 0) {
// The first item is typically the framework resources,
@@ -565,7 +565,7 @@ bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const {
ass = const_cast<AssetManager*>(this)->
mZipSet.getZipResourceTableAsset(ap.path);
if (ass == NULL) {
- ALOGV("loading resource table %s\n", ap.path.string());
+ ALOGV("loading resource table %s\n", ap.path.c_str());
ass = const_cast<AssetManager*>(this)->
openNonAssetInPathLocked("resources.arsc",
Asset::ACCESS_BUFFER,
@@ -580,7 +580,7 @@ bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const {
// If this is the first resource table in the asset
// manager, then we are going to cache it so that we
// can quickly copy it out for others.
- ALOGV("Creating shared resources for %s", ap.path.string());
+ ALOGV("Creating shared resources for %s", ap.path.c_str());
sharedRes = new ResTable();
sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
#ifdef __ANDROID__
@@ -589,14 +589,14 @@ bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const {
String8 overlaysListPath(data);
overlaysListPath.appendPath(kResourceCache);
overlaysListPath.appendPath("overlays.list");
- addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx);
+ addSystemOverlays(overlaysListPath.c_str(), ap.path, sharedRes, nextEntryIdx);
#endif
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
}
} else {
- ALOGV("loading resource table %s\n", ap.path.string());
+ ALOGV("loading resource table %s\n", ap.path.c_str());
ass = const_cast<AssetManager*>(this)->
openNonAssetInPathLocked("resources.arsc",
Asset::ACCESS_BUFFER,
@@ -607,10 +607,10 @@ bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const {
if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
if (sharedRes != NULL) {
- ALOGV("Copying existing resources for %s", ap.path.string());
+ ALOGV("Copying existing resources for %s", ap.path.c_str());
mResources->add(sharedRes, ap.isSystemAsset);
} else {
- ALOGV("Parsing resources for %s", ap.path.string());
+ ALOGV("Parsing resources for %s", ap.path.c_str());
mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
}
onlyEmptyResources = false;
@@ -692,9 +692,9 @@ Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
ass = const_cast<AssetManager*>(this)->
openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
if (ass) {
- ALOGV("loading idmap %s\n", ap.idmap.string());
+ ALOGV("loading idmap %s\n", ap.idmap.c_str());
} else {
- ALOGW("failed to load idmap %s\n", ap.idmap.string());
+ ALOGW("failed to load idmap %s\n", ap.idmap.c_str());
}
}
return ass;
@@ -812,7 +812,7 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m
ZipFileRO* pZip = getZipFileLocked(ap);
if (pZip != NULL) {
ALOGV("GOT zip, checking NA '%s'", (const char*) path);
- ZipEntryRO entry = pZip->findEntryByName(path.string());
+ ZipEntryRO entry = pZip->findEntryByName(path.c_str());
if (entry != NULL) {
ALOGV("FOUND NA in Zip file for %s", (const char*) path);
pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
@@ -823,7 +823,7 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m
if (pAsset != NULL) {
/* create a "source" name, for debug/display */
pAsset->setAssetSource(
- createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""),
+ createZipSourceNameLocked(ZipSet::getPathName(ap.path.c_str()), String8(""),
String8(fileName)));
}
}
@@ -870,7 +870,7 @@ ZipFileRO* AssetManager::getZipFileLocked(asset_path& ap)
}
if (ap.rawFd < 0) {
- ALOGV("getZipFileLocked: Creating new zip from path %s", ap.path.string());
+ ALOGV("getZipFileLocked: Creating new zip from path %s", ap.path.c_str());
ap.zip = mZipSet.getSharedZip(ap.path);
} else {
ALOGV("getZipFileLocked: Creating new zip from fd %d", ap.rawFd);
@@ -897,12 +897,12 @@ Asset* AssetManager::openAssetFromFileLocked(const String8& pathName,
{
Asset* pAsset = NULL;
- if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) {
+ if (strcasecmp(pathName.getPathExtension().c_str(), ".gz") == 0) {
//printf("TRYING '%s'\n", (const char*) pathName);
- pAsset = Asset::createFromCompressedFile(pathName.string(), mode);
+ pAsset = Asset::createFromCompressedFile(pathName.c_str(), mode);
} else {
//printf("TRYING '%s'\n", (const char*) pathName);
- pAsset = Asset::createFromFile(pathName.string(), mode);
+ pAsset = Asset::createFromFile(pathName.c_str(), mode);
}
return pAsset;
@@ -940,12 +940,12 @@ Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
if (method == ZipFileRO::kCompressStored) {
pAsset = Asset::createFromUncompressedMap(std::move(*dataMap), mode);
- ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
+ ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.c_str(),
dataMap->file_name(), mode, pAsset.get());
} else {
pAsset = Asset::createFromCompressedMap(std::move(*dataMap),
static_cast<size_t>(uncompressedLen), mode);
- ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
+ ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.c_str(),
dataMap->file_name(), mode, pAsset.get());
}
if (pAsset == NULL) {
@@ -993,10 +993,10 @@ AssetDir* AssetManager::openDir(const char* dirName)
i--;
const asset_path& ap = mAssetPaths.itemAt(i);
if (ap.type == kFileTypeRegular) {
- ALOGV("Adding directory %s from zip %s", dirName, ap.path.string());
+ ALOGV("Adding directory %s from zip %s", dirName, ap.path.c_str());
scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName);
} else {
- ALOGV("Adding directory %s from dir %s", dirName, ap.path.string());
+ ALOGV("Adding directory %s from dir %s", dirName, ap.path.c_str());
scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName);
}
}
@@ -1042,10 +1042,10 @@ AssetDir* AssetManager::openNonAssetDir(const int32_t cookie, const char* dirNam
if (which < mAssetPaths.size()) {
const asset_path& ap = mAssetPaths.itemAt(which);
if (ap.type == kFileTypeRegular) {
- ALOGV("Adding directory %s from zip %s", dirName, ap.path.string());
+ ALOGV("Adding directory %s from zip %s", dirName, ap.path.c_str());
scanAndMergeZipLocked(pMergedInfo, ap, NULL, dirName);
} else {
- ALOGV("Adding directory %s from dir %s", dirName, ap.path.string());
+ ALOGV("Adding directory %s from dir %s", dirName, ap.path.c_str());
scanAndMergeDirLocked(pMergedInfo, ap, NULL, dirName);
}
}
@@ -1075,7 +1075,7 @@ bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMerg
{
assert(pMergedInfo != NULL);
- //printf("scanAndMergeDir: %s %s %s\n", ap.path.string(), rootDir, dirName);
+ //printf("scanAndMergeDir: %s %s %s\n", ap.path.c_str(), rootDir, dirName);
String8 path = createPathNameLocked(ap, rootDir);
if (dirName[0] != '\0')
@@ -1100,7 +1100,7 @@ bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMerg
const char* name;
int nameLen;
- name = pContents->itemAt(i).getFileName().string();
+ name = pContents->itemAt(i).getFileName().c_str();
nameLen = strlen(name);
if (nameLen > exclExtLen &&
strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0)
@@ -1111,8 +1111,8 @@ bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMerg
matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match);
if (matchIdx > 0) {
ALOGV("Excluding '%s' [%s]\n",
- pMergedInfo->itemAt(matchIdx).getFileName().string(),
- pMergedInfo->itemAt(matchIdx).getSourceName().string());
+ pMergedInfo->itemAt(matchIdx).getFileName().c_str(),
+ pMergedInfo->itemAt(matchIdx).getSourceName().c_str());
pMergedInfo->removeAt(matchIdx);
} else {
//printf("+++ no match on '%s'\n", (const char*) match);
@@ -1150,9 +1150,9 @@ SortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& pat
struct dirent* entry;
FileType fileType;
- ALOGV("Scanning dir '%s'\n", path.string());
+ ALOGV("Scanning dir '%s'\n", path.c_str());
- dir = opendir(path.string());
+ dir = opendir(path.c_str());
if (dir == NULL)
return NULL;
@@ -1176,7 +1176,7 @@ SortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& pat
fileType = kFileTypeUnknown;
#else
// stat the file
- fileType = ::getFileType(path.appendPathCopy(entry->d_name).string());
+ fileType = ::getFileType(path.appendPathCopy(entry->d_name).c_str());
#endif
if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
@@ -1184,7 +1184,7 @@ SortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& pat
AssetDir::FileInfo info;
info.set(String8(entry->d_name), fileType);
- if (strcasecmp(info.getFileName().getPathExtension().string(), ".gz") == 0)
+ if (strcasecmp(info.getFileName().getPathExtension().c_str(), ".gz") == 0)
info.setFileName(info.getFileName().getBasePath());
info.setSourceName(path.appendPathCopy(info.getFileName()));
pContents->add(info);
@@ -1212,11 +1212,11 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
pZip = mZipSet.getZip(ap.path);
if (pZip == NULL) {
- ALOGW("Failure opening zip %s\n", ap.path.string());
+ ALOGW("Failure opening zip %s\n", ap.path.c_str());
return false;
}
- zipName = ZipSet::getPathName(ap.path.string());
+ zipName = ZipSet::getPathName(ap.path.c_str());
/* convert "sounds" to "rootDir/sounds" */
if (rootDir != NULL) dirName = rootDir;
@@ -1240,7 +1240,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
*/
int dirNameLen = dirName.length();
void *iterationCookie;
- if (!pZip->startIteration(&iterationCookie, dirName.string(), NULL)) {
+ if (!pZip->startIteration(&iterationCookie, dirName.c_str(), NULL)) {
ALOGW("ZipFileRO::startIteration returned false");
return false;
}
@@ -1254,7 +1254,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
ALOGE("ARGH: name too long?\n");
continue;
}
- //printf("Comparing %s in %s?\n", nameBuf, dirName.string());
+ //printf("Comparing %s in %s?\n", nameBuf, dirName.c_str());
if (dirNameLen == 0 || nameBuf[dirNameLen] == '/')
{
const char* cp;
@@ -1275,7 +1275,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
createZipSourceNameLocked(zipName, dirName, info.getFileName()));
contents.add(info);
- //printf("FOUND: file '%s'\n", info.getFileName().string());
+ //printf("FOUND: file '%s'\n", info.getFileName().c_str());
} else {
/* this is a subdir; add it if we don't already have it*/
String8 subdirName(cp, nextSlash - cp);
@@ -1291,7 +1291,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
dirs.add(subdirName);
}
- //printf("FOUND: dir '%s'\n", subdirName.string());
+ //printf("FOUND: dir '%s'\n", subdirName.c_str());
}
}
}
@@ -1427,10 +1427,10 @@ AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
if (kIsDebug) {
ALOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
}
- ALOGV("+++ opening zip '%s'\n", mPath.string());
- mZipFile = ZipFileRO::open(mPath.string());
+ ALOGV("+++ opening zip '%s'\n", mPath.c_str());
+ mZipFile = ZipFileRO::open(mPath.c_str());
if (mZipFile == NULL) {
- ALOGD("failed to open Zip archive '%s'\n", mPath.string());
+ ALOGD("failed to open Zip archive '%s'\n", mPath.c_str());
}
}
@@ -1441,11 +1441,11 @@ AssetManager::SharedZip::SharedZip(int fd, const String8& path)
if (kIsDebug) {
ALOGI("Creating SharedZip %p fd=%d %s\n", this, fd, (const char*)mPath);
}
- ALOGV("+++ opening zip fd=%d '%s'\n", fd, mPath.string());
- mZipFile = ZipFileRO::openFd(fd, mPath.string());
+ ALOGV("+++ opening zip fd=%d '%s'\n", fd, mPath.c_str());
+ mZipFile = ZipFileRO::openFd(fd, mPath.c_str());
if (mZipFile == NULL) {
::close(fd);
- ALOGD("failed to open Zip archive fd=%d '%s'\n", fd, mPath.string());
+ ALOGD("failed to open Zip archive fd=%d '%s'\n", fd, mPath.c_str());
}
}
@@ -1520,7 +1520,7 @@ ResTable* AssetManager::SharedZip::setResourceTable(ResTable* res)
bool AssetManager::SharedZip::isUpToDate()
{
- time_t modWhen = getFileModDate(mPath.string());
+ time_t modWhen = getFileModDate(mPath.c_str());
return mModWhen == modWhen;
}
@@ -1551,7 +1551,7 @@ AssetManager::SharedZip::~SharedZip()
}
if (mZipFile != NULL) {
delete mZipFile;
- ALOGV("Closed '%s'\n", mPath.string());
+ ALOGV("Closed '%s'\n", mPath.c_str());
}
}
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index 76a430ee9f0e..fec0e772674d 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -106,8 +106,8 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
k = key;
}
if (kIsDebug) {
- ALOGD("Writing header: prefix='%s' key='%s' dataSize=%zu", m_keyPrefix.string(),
- key.string(), dataSize);
+ ALOGD("Writing header: prefix='%s' key='%s' dataSize=%zu", m_keyPrefix.c_str(),
+ key.c_str(), dataSize);
}
entity_header_v1 header;
@@ -128,7 +128,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
m_pos += amt;
if (kIsDebug) ALOGI("writing entity header key, %zd bytes", keyLen+1);
- amt = write(m_fd, k.string(), keyLen+1);
+ amt = write(m_fd, k.c_str(), keyLen+1);
if (amt != keyLen+1) {
m_status = errno;
return m_status;
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index e80e9486c8b2..35826090d6e5 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -179,7 +179,7 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
}
// filename is not NULL terminated, but it is padded
- amt = write(fd, name.string(), nameLen);
+ amt = write(fd, name.c_str(), nameLen);
if (amt != nameLen) {
ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
return 1;
@@ -203,7 +203,7 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
static int
write_delete_file(BackupDataWriter* dataStream, const String8& key)
{
- LOGP("write_delete_file %s\n", key.string());
+ LOGP("write_delete_file %s\n", key.c_str());
return dataStream->WriteEntityHeader(key, -1);
}
@@ -211,7 +211,7 @@ static int
write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
char const* realFilename)
{
- LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
+ LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.c_str(), mode);
const int bufsize = 4*1024;
int err;
@@ -365,7 +365,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
r.s.size = st.st_size;
if (newSnapshot.indexOfKey(key) >= 0) {
- LOGP("back_up_files key already in use '%s'", key.string());
+ LOGP("back_up_files key already in use '%s'", key.c_str());
return -1;
}
@@ -390,30 +390,30 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
int cmp = p.compare(q);
if (cmp < 0) {
// file present in oldSnapshot, but not present in newSnapshot
- LOGP("file removed: %s", p.string());
+ LOGP("file removed: %s", p.c_str());
write_delete_file(dataStream, p);
n++;
} else if (cmp > 0) {
// file added
- LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32);
- write_update_file(dataStream, q, g.file.string());
+ LOGP("file added: %s crc=0x%08x", g.file.c_str(), g.s.crc32);
+ write_update_file(dataStream, q, g.file.c_str());
m++;
} else {
// same file exists in both old and new; check whether to update
const FileState& f = oldSnapshot.valueAt(n);
- LOGP("%s", q.string());
+ LOGP("%s", q.c_str());
LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
|| f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
- int fd = open(g.file.string(), O_RDONLY);
+ int fd = open(g.file.c_str(), O_RDONLY);
if (fd < 0) {
- ALOGE("Unable to read file for backup: %s", g.file.string());
+ ALOGE("Unable to read file for backup: %s", g.file.c_str());
} else {
- write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
+ write_update_file(dataStream, fd, g.s.mode, p, g.file.c_str());
close(fd);
}
}
@@ -432,7 +432,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
while (m<M) {
const String8& q = newSnapshot.keyAt(m);
FileRec& g = newSnapshot.editValueAt(m);
- write_update_file(dataStream, q, g.file.string());
+ write_update_file(dataStream, q, g.file.c_str());
m++;
}
@@ -483,7 +483,7 @@ int write_tarfile(const String8& packageName, const String8& domain,
BackupDataWriter* writer)
{
// In the output stream everything is stored relative to the root
- const char* relstart = filepath.string() + rootpath.length();
+ const char* relstart = filepath.c_str() + rootpath.length();
if (*relstart == '/') relstart++; // won't be true when path == rootpath
String8 relpath(relstart);
@@ -514,9 +514,9 @@ int write_tarfile(const String8& packageName, const String8& domain,
int err = 0;
struct stat64 s;
- if (lstat64(filepath.string(), &s) != 0) {
+ if (lstat64(filepath.c_str(), &s) != 0) {
err = errno;
- ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
+ ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.c_str());
return err;
}
@@ -541,10 +541,10 @@ int write_tarfile(const String8& packageName, const String8& domain,
// !!! TODO: use mmap when possible to avoid churning the buffer cache
// !!! TODO: this will break with symlinks; need to use readlink(2)
- int fd = open(filepath.string(), O_RDONLY);
+ int fd = open(filepath.c_str(), O_RDONLY);
if (fd < 0) {
err = errno;
- ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
+ ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.c_str());
return err;
}
@@ -592,7 +592,7 @@ int write_tarfile(const String8& packageName, const String8& domain,
} else if (S_ISREG(s.st_mode)) {
type = '0'; // tar magic: '0' == normal file
} else {
- ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
+ ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.c_str());
goto cleanup;
}
buf[156] = type;
@@ -620,16 +620,16 @@ int write_tarfile(const String8& packageName, const String8& domain,
// [ 345 : 155 ] filename path prefix
// We only use the prefix area if fullname won't fit in the path
if (fullname.length() > 100) {
- strncpy(buf, relpath.string(), 100);
- strncpy(buf + 345, prefix.string(), 155);
+ strncpy(buf, relpath.c_str(), 100);
+ strncpy(buf + 345, prefix.c_str(), 155);
} else {
- strncpy(buf, fullname.string(), 100);
+ strncpy(buf, fullname.c_str(), 100);
}
}
// [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
- ALOGI(" Name: %s", fullname.string());
+ ALOGI(" Name: %s", fullname.c_str());
// If we're using a pax extended header, build & write that here; lengths are
// already preflighted
@@ -647,7 +647,7 @@ int write_tarfile(const String8& packageName, const String8& domain,
// fullname was generated above with the ustar paths
paxLen += write_pax_header_entry(paxData + paxLen, PAXDATA_SIZE - paxLen,
- "path", fullname.string());
+ "path", fullname.c_str());
// Now we know how big the pax data is
@@ -656,9 +656,9 @@ int write_tarfile(const String8& packageName, const String8& domain,
String8 leaf = fullname.getPathLeaf();
memset(paxHeader, 0, 100); // rewrite the name area
- snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
+ snprintf(paxHeader, 100, "PaxHeader/%s", leaf.c_str());
memset(paxHeader + 345, 0, 155); // rewrite the prefix area
- strncpy(paxHeader + 345, prefix.string(), 155);
+ strncpy(paxHeader + 345, prefix.c_str(), 155);
paxHeader[156] = 'x'; // mark it as a pax extended header
@@ -691,12 +691,12 @@ int write_tarfile(const String8& packageName, const String8& domain,
ssize_t nRead = read(fd, buf, toRead);
if (nRead < 0) {
err = errno;
- ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
+ ALOGE("Unable to read file [%s], err=%d (%s)", filepath.c_str(),
err, strerror(err));
break;
} else if (nRead == 0) {
ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
- filepath.string());
+ filepath.c_str());
err = EIO;
break;
}
@@ -762,7 +762,7 @@ RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
file_metadata_v1 metadata;
amt = in->ReadEntityData(&metadata, sizeof(metadata));
if (amt != sizeof(metadata)) {
- ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
+ ALOGW("Could not read metadata for %s -- %ld / %s", filename.c_str(),
(long)amt, strerror(errno));
return EIO;
}
@@ -779,9 +779,9 @@ RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
// Write the file and compute the crc
crc = crc32(0L, Z_NULL, 0);
- fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
+ fd = open(filename.c_str(), O_CREAT|O_RDWR|O_TRUNC, mode);
if (fd == -1) {
- ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
+ ALOGW("Could not open file %s -- %s", filename.c_str(), strerror(errno));
return errno;
}
@@ -789,7 +789,7 @@ RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
err = write(fd, buf, amt);
if (err != amt) {
close(fd);
- ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
+ ALOGW("Error '%s' writing '%s'", strerror(errno), filename.c_str());
return errno;
}
crc = crc32(crc, (Bytef*)buf, amt);
@@ -798,9 +798,9 @@ RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
close(fd);
// Record for the snapshot
- err = stat(filename.string(), &st);
+ err = stat(filename.c_str(), &st);
if (err != 0) {
- ALOGW("Error stating file that we just created %s", filename.string());
+ ALOGW("Error stating file that we just created %s", filename.c_str());
return errno;
}
@@ -1104,9 +1104,9 @@ backup_helper_test_four()
fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
" actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
- states[i].crc32, name.length(), filenames[i].string(),
+ states[i].crc32, name.length(), filenames[i].c_str(),
state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
- state.nameLen, name.string());
+ state.nameLen, name.c_str());
matched = false;
}
}
@@ -1152,9 +1152,9 @@ test_write_header_and_entity(BackupDataWriter& writer, const char* str)
return err;
}
- err = writer.WriteEntityData(text.string(), text.length()+1);
+ err = writer.WriteEntityData(text.c_str(), text.length()+1);
if (err != 0) {
- fprintf(stderr, "write failed for data '%s'\n", text.string());
+ fprintf(stderr, "write failed for data '%s'\n", text.c_str());
return errno;
}
@@ -1230,7 +1230,7 @@ test_read_header_and_entity(BackupDataReader& reader, const char* str)
goto finished;
}
if (string != str) {
- fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
+ fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.c_str());
err = EINVAL;
goto finished;
}
diff --git a/libs/androidfw/ConfigDescription.cpp b/libs/androidfw/ConfigDescription.cpp
index cf2fd6f59b87..e08030c4cca5 100644
--- a/libs/androidfw/ConfigDescription.cpp
+++ b/libs/androidfw/ConfigDescription.cpp
@@ -905,7 +905,7 @@ std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const {
std::string ConfigDescription::to_string() const {
const String8 str = toString();
- return std::string(str.string(), str.size());
+ return std::string(str.c_str(), str.size());
}
bool ConfigDescription::Dominates(const ConfigDescription& o) const {
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 2a6dc7b95c07..5e645cceea2d 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -84,7 +84,7 @@ status_t CursorWindow::maybeInflate() {
String8 ashmemName("CursorWindow: ");
ashmemName.append(mName);
- ashmemFd = ashmem_create_region(ashmemName.string(), mInflatedSize);
+ ashmemFd = ashmem_create_region(ashmemName.c_str(), mInflatedSize);
if (ashmemFd < 0) {
PLOG(ERROR) << "Failed ashmem_create_region";
goto fail_silent;
diff --git a/libs/androidfw/ObbFile.cpp b/libs/androidfw/ObbFile.cpp
index 95332a35eb7d..c6a9632ee7b7 100644
--- a/libs/androidfw/ObbFile.cpp
+++ b/libs/androidfw/ObbFile.cpp
@@ -217,7 +217,7 @@ bool ObbFile::parseObbFile(int fd)
free(scanBuf);
#ifdef DEBUG
- ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
+ ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.c_str(), mVersion);
#endif
return true;
@@ -288,7 +288,7 @@ bool ObbFile::writeTo(int fd)
return false;
}
- if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
+ if (write(fd, mPackageName.c_str(), packageNameLen) != (ssize_t)packageNameLen) {
ALOGW("couldn't write package name: %s\n", strerror(errno));
return false;
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 5a636128e076..112058fc65c7 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1042,7 +1042,7 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
if (kDebugStringPoolNoisy) {
- ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
+ ALOGI("indexOfString UTF-8: %s", String8(str, strLen).c_str());
}
// The string pool contains UTF 8 strings; we don't want to cause
@@ -1103,7 +1103,7 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
ALOGI("Looking at %s, i=%d\n", s->data(), i);
}
if (str8Len == s->size()
- && memcmp(s->data(), str8.string(), str8Len) == 0) {
+ && memcmp(s->data(), str8.c_str(), str8Len) == 0) {
if (kDebugStringPoolNoisy) {
ALOGI("MATCH!");
}
@@ -1115,7 +1115,7 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
} else {
if (kDebugStringPoolNoisy) {
- ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string());
+ ALOGI("indexOfString UTF-16: %s", String8(str, strLen).c_str());
}
if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
@@ -1133,7 +1133,7 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1;
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
- String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h);
+ String8(s->data(), s->size()).c_str(), c, (int)l, (int)mid, (int)h);
}
if (c == 0) {
if (kDebugStringPoolNoisy) {
@@ -1157,7 +1157,7 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
return base::unexpected(s.error());
}
if (kDebugStringPoolNoisy) {
- ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i);
+ ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).c_str(), i);
}
if (s.has_value() && strLen == s->size() &&
strzcmp16(s->data(), s->size(), str, strLen) == 0) {
@@ -1525,8 +1525,8 @@ ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
{
String16 nsStr(ns != NULL ? ns : "");
String16 attrStr(attr);
- return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
- attrStr.string(), attrStr.size());
+ return indexOfAttribute(ns ? nsStr.c_str() : NULL, ns ? nsStr.size() : 0,
+ attrStr.c_str(), attrStr.size());
}
ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
@@ -1544,8 +1544,8 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
}
attr8 = String8(attr, attrLen);
if (kDebugStringPoolNoisy) {
- ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.string(), nsLen,
- attr8.string(), attrLen);
+ ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.c_str(), nsLen,
+ attr8.c_str(), attrLen);
}
for (size_t i=0; i<N; i++) {
size_t curNsLen = 0, curAttrLen = 0;
@@ -1555,7 +1555,7 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
ALOGI(" curNs=%s (%zu), curAttr=%s (%zu)", curNs, curNsLen, curAttr, curAttrLen);
}
if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
- && memcmp(attr8.string(), curAttr, attrLen) == 0) {
+ && memcmp(attr8.c_str(), curAttr, attrLen) == 0) {
if (ns == NULL) {
if (curNs == NULL) {
if (kDebugStringPoolNoisy) {
@@ -1565,8 +1565,8 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
}
} else if (curNs != NULL) {
//printf(" --> ns=%s, curNs=%s\n",
- // String8(ns).string(), String8(curNs).string());
- if (memcmp(ns8.string(), curNs, nsLen) == 0) {
+ // String8(ns).c_str(), String8(curNs).c_str());
+ if (memcmp(ns8.c_str(), curNs, nsLen) == 0) {
if (kDebugStringPoolNoisy) {
ALOGI(" FOUND!");
}
@@ -1578,8 +1578,8 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
} else {
if (kDebugStringPoolNoisy) {
ALOGI("indexOfAttribute UTF16 %s (%zu) / %s (%zu)",
- String8(ns, nsLen).string(), nsLen,
- String8(attr, attrLen).string(), attrLen);
+ String8(ns, nsLen).c_str(), nsLen,
+ String8(attr, attrLen).c_str(), attrLen);
}
for (size_t i=0; i<N; i++) {
size_t curNsLen = 0, curAttrLen = 0;
@@ -1587,8 +1587,8 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
const char16_t* curAttr = getAttributeName(i, &curAttrLen);
if (kDebugStringPoolNoisy) {
ALOGI(" curNs=%s (%zu), curAttr=%s (%zu)",
- String8(curNs, curNsLen).string(), curNsLen,
- String8(curAttr, curAttrLen).string(), curAttrLen);
+ String8(curNs, curNsLen).c_str(), curNsLen,
+ String8(curAttr, curAttrLen).c_str(), curAttrLen);
}
if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
&& (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
@@ -1601,7 +1601,7 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
}
} else if (curNs != NULL) {
//printf(" --> ns=%s, curNs=%s\n",
- // String8(ns).string(), String8(curNs).string());
+ // String8(ns).c_str(), String8(curNs).c_str());
if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
if (kDebugStringPoolNoisy) {
ALOGI(" FOUND!");
@@ -4475,7 +4475,7 @@ bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* ou
return false;
}
- outName->package = grp->name.string();
+ outName->package = grp->name.c_str();
outName->packageLen = grp->name.size();
if (allowUtf8) {
outName->type8 = UnpackOptionalString(entry.typeStr.string8(), &outName->typeLen);
@@ -4575,7 +4575,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
outValue->dataType,
outValue->dataType == Res_value::TYPE_STRING ?
String8(UnpackOptionalString(
- entry.package->header->values.stringAt(outValue->data), &len)).string() :
+ entry.package->header->values.stringAt(outValue->data), &len)).c_str() :
"",
outValue->data);
}
@@ -4944,7 +4944,7 @@ void ResTable::setParameters(const ResTable_config* params)
AutoMutex _lock2(mFilteredConfigLock);
if (kDebugTableGetEntry) {
- ALOGI("Setting parameters: %s\n", params->toString().string());
+ ALOGI("Setting parameters: %s\n", params->toString().c_str());
}
mParams = *params;
for (size_t p = 0; p < mPackageGroups.size(); p++) {
@@ -5055,7 +5055,7 @@ nope:
if (name[1] == 'i' && name[2] == 'n'
&& name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
&& name[6] == '_') {
- int index = atoi(String8(name + 7, nameLen - 7).string());
+ int index = atoi(String8(name + 7, nameLen - 7).c_str());
if (Res_CHECKID(index)) {
ALOGW("Array resource index: %d is too large.",
index);
@@ -5121,9 +5121,9 @@ nope:
if (kDebugTableNoisy) {
printf("Looking for identifier: type=%s, name=%s, package=%s\n",
- String8(type, typeLen).string(),
- String8(name, nameLen).string(),
- String8(package, packageLen).string());
+ String8(type, typeLen).c_str(),
+ String8(name, nameLen).c_str(),
+ String8(package, packageLen).c_str());
}
const String16 attr("attr");
@@ -5134,9 +5134,9 @@ nope:
const PackageGroup* group = mPackageGroups[ig];
if (strzcmp16(package, packageLen,
- group->name.string(), group->name.size())) {
+ group->name.c_str(), group->name.size())) {
if (kDebugTableNoisy) {
- printf("Skipping package group: %s\n", String8(group->name).string());
+ printf("Skipping package group: %s\n", String8(group->name).c_str());
}
continue;
}
@@ -5161,8 +5161,8 @@ nope:
}
return identifier;
}
- } while (strzcmp16(attr.string(), attr.size(), targetType, targetTypeLen) == 0
- && (targetType = attrPrivate.string())
+ } while (strzcmp16(attr.c_str(), attr.size(), targetType, targetTypeLen) == 0
+ && (targetType = attrPrivate.c_str())
&& (targetTypeLen = attrPrivate.size())
);
}
@@ -5610,7 +5610,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
}
}
- //printf("Value for: %s\n", String8(s, len).string());
+ //printf("Value for: %s\n", String8(s, len).c_str());
uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
@@ -5665,7 +5665,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
// be to any other type; we just need to count on the client making
// sure the referenced type is correct.
- //printf("Looking up ref: %s\n", String8(s, len).string());
+ //printf("Looking up ref: %s\n", String8(s, len).c_str());
// It's a reference!
if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
@@ -5705,8 +5705,8 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
}
uint32_t specFlags = 0;
- uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
- type.size(), package.string(), package.size(), &specFlags);
+ uint32_t rid = identifierForName(name.c_str(), name.size(), type.c_str(),
+ type.size(), package.c_str(), package.size(), &specFlags);
if (rid != 0) {
if (enforcePrivate) {
if (accessor == NULL || accessor->getAssetsPackage() != package) {
@@ -5725,8 +5725,8 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
Res_GETTYPE(rid), Res_GETENTRY(rid));
if (kDebugTableNoisy) {
ALOGI("Incl %s:%s/%s: 0x%08x\n",
- String8(package).string(), String8(type).string(),
- String8(name).string(), rid);
+ String8(package).c_str(), String8(type).c_str(),
+ String8(name).c_str(), rid);
}
}
@@ -5744,8 +5744,8 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
if (rid != 0) {
if (kDebugTableNoisy) {
ALOGI("Pckg %s:%s/%s: 0x%08x\n",
- String8(package).string(), String8(type).string(),
- String8(name).string(), rid);
+ String8(package).c_str(), String8(type).c_str(),
+ String8(name).c_str(), rid);
}
uint32_t packageId = Res_GETPACKAGE(rid) + 1;
if (packageId == 0x00) {
@@ -5834,7 +5834,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
}
} else {
outValue->data = color;
- //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
+ //printf("Color input=%s, output=0x%x\n", String8(s, len).c_str(), color);
return true;
}
} else {
@@ -5846,8 +5846,8 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
#if 0
fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
"Resource File", //(const char*)in->getPrintableSource(),
- String8(*curTag).string(),
- String8(s, len).string());
+ String8(*curTag).c_str(),
+ String8(s, len).c_str());
#endif
return false;
}
@@ -5861,7 +5861,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
// be to any other type; we just need to count on the client making
// sure the referenced type is correct.
- //printf("Looking up attr: %s\n", String8(s, len).string());
+ //printf("Looking up attr: %s\n", String8(s, len).c_str());
static const String16 attr16("attr");
String16 package, type, name;
@@ -5874,13 +5874,13 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
}
//printf("Pkg: %s, Type: %s, Name: %s\n",
- // String8(package).string(), String8(type).string(),
- // String8(name).string());
+ // String8(package).c_str(), String8(type).c_str(),
+ // String8(name).c_str());
uint32_t specFlags = 0;
uint32_t rid =
- identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size(), &specFlags);
+ identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size(), &specFlags);
if (rid != 0) {
if (enforcePrivate) {
if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
@@ -6038,8 +6038,8 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
if (getResourceName(bag->map.name.ident, false, &rname)) {
#if 0
printf("Matching %s against %s (0x%08x)\n",
- String8(s, len).string(),
- String8(rname.name, rname.nameLen).string(),
+ String8(s, len).c_str(),
+ String8(rname.name, rname.nameLen).c_str(),
bag->map.name.ident);
#endif
if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
@@ -6082,7 +6082,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
while (pos < end && *pos != '|') {
pos++;
}
- //printf("Looking for: %s\n", String8(start, pos-start).string());
+ //printf("Looking for: %s\n", String8(start, pos-start).c_str());
const bag_entry* bagi = bag;
ssize_t i;
for (i=0; i<cnt; i++, bagi++) {
@@ -6091,8 +6091,8 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
if (getResourceName(bagi->map.name.ident, false, &rname)) {
#if 0
printf("Matching %s against %s (0x%08x)\n",
- String8(start,pos-start).string(),
- String8(rname.name, rname.nameLen).string(),
+ String8(start,pos-start).c_str(),
+ String8(rname.name, rname.nameLen).c_str(),
bagi->map.name.ident);
#endif
if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
@@ -6419,7 +6419,7 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMi
}
static bool compareString8AndCString(const String8& str, const char* cStr) {
- return strcmp(str.string(), cStr) < 0;
+ return strcmp(str.c_str(), cStr) < 0;
}
void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales,
@@ -6433,7 +6433,7 @@ void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales,
const auto endIter = locales->end();
auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
- if (iter == endIter || strcmp(iter->string(), locale) != 0) {
+ if (iter == endIter || strcmp(iter->c_str(), locale) != 0) {
locales->insertAt(String8(locale), std::distance(beginIter, iter));
}
});
@@ -7030,7 +7030,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
ResTable_config thisConfig;
thisConfig.copyFromDtoH(type->config);
ALOGI("Adding config to type %d: %s\n", type->id,
- thisConfig.toString().string());
+ thisConfig.toString().c_str());
}
}
} else {
@@ -7107,7 +7107,7 @@ status_t DynamicRefTable::load(const ResTable_lib_header* const header)
char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
if (kDebugLibNoisy) {
- ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
+ ALOGV("Found lib entry %s with id %d\n", String8(tmpName).c_str(),
dtohl(entry->packageId));
}
if (packageId >= 256) {
@@ -7386,7 +7386,7 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
current_res.nameLen,
current_res.type,
current_res.typeLen,
- targetPackageName.string(),
+ targetPackageName.c_str(),
targetPackageName.size(),
&typeSpecFlags);
@@ -7493,7 +7493,7 @@ bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
}
-#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
+#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).c_str())
#define CHAR16_ARRAY_EQ(constant, var, len) \
(((len) == (sizeof(constant)/sizeof((constant)[0]))) && (0 == memcmp((var), (constant), (len))))
@@ -7588,13 +7588,13 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const
const char* str8 = UnpackOptionalString(pkg->header->values.string8At(
value.data), &len);
if (str8 != NULL) {
- printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
+ printf("(string8) \"%s\"\n", normalizeForOutput(str8).c_str());
} else {
const char16_t* str16 = UnpackOptionalString(pkg->header->values.stringAt(
value.data), &len);
if (str16 != NULL) {
printf("(string16) \"%s\"\n",
- normalizeForOutput(String8(str16, len).string()).string());
+ normalizeForOutput(String8(str16, len).c_str()).c_str());
} else {
printf("(string) null\n");
}
@@ -7635,7 +7635,7 @@ void ResTable::print(bool inclValues) const
const PackageGroup* pg = mPackageGroups[pgIndex];
printf("Package Group %d id=0x%02x packageCount=%d name=%s\n",
(int)pgIndex, pg->id, (int)pg->packages.size(),
- String8(pg->name).string());
+ String8(pg->name).c_str());
const KeyedVector<String16, uint8_t>& refEntries = pg->dynamicRefTable.entries();
const size_t refEntryCount = refEntries.size();
@@ -7644,7 +7644,7 @@ void ResTable::print(bool inclValues) const
for (size_t refIndex = 0; refIndex < refEntryCount; refIndex++) {
printf(" 0x%02x -> %s\n",
refEntries.valueAt(refIndex),
- String8(refEntries.keyAt(refIndex)).string());
+ String8(refEntries.keyAt(refIndex)).c_str());
}
printf("\n");
}
@@ -7670,7 +7670,7 @@ void ResTable::print(bool inclValues) const
strcpy16_dtoh(tmpName, pkg->package->name,
sizeof(pkg->package->name)/sizeof(pkg->package->name[0]));
printf(" Package %d id=0x%02x name=%s\n", (int)pkgIndex,
- pkg->package->id, String8(tmpName).string());
+ pkg->package->id, String8(tmpName).c_str());
}
for (size_t typeIndex = 0; typeIndex < pg->types.size(); typeIndex++) {
@@ -7712,7 +7712,7 @@ void ResTable::print(bool inclValues) const
printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
resID,
CHAR16_TO_CSTR(resName.package, resName.packageLen),
- type8.string(), name8.string(),
+ type8.c_str(), name8.c_str(),
dtohl(typeConfigs->typeSpecFlags[entryIndex]));
} else {
printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
@@ -7733,7 +7733,7 @@ void ResTable::print(bool inclValues) const
String8 configStr = thisConfig.toString();
printf(" config %s", configStr.size() > 0
- ? configStr.string() : "(default)");
+ ? configStr.c_str() : "(default)");
if (type->flags != 0u) {
printf(" flags=0x%02x", type->flags);
if (type->flags & ResTable_type::FLAG_SPARSE) {
@@ -7807,7 +7807,7 @@ void ResTable::print(bool inclValues) const
}
printf(" resource 0x%08x %s:%s/%s: ", resID,
CHAR16_TO_CSTR(resName.package, resName.packageLen),
- type8.string(), name8.string());
+ type8.c_str(), name8.c_str());
} else {
printf(" INVALID RESOURCE 0x%08x: ", resID);
}
diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h
index 19febcdee77e..f3776b5401f3 100644
--- a/libs/androidfw/include/androidfw/Asset.h
+++ b/libs/androidfw/include/androidfw/Asset.h
@@ -135,7 +135,7 @@ public:
* This is NOT intended to be used for anything except debug output.
* DO NOT try to parse this or use it to open a file.
*/
- const char* getAssetSource(void) const { return mAssetSource.string(); }
+ const char* getAssetSource(void) const { return mAssetSource.c_str(); }
/*
* Create the asset from a file descriptor.
diff --git a/libs/androidfw/include/androidfw/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h
index 7fbd7c08ea69..83a80ced855b 100644
--- a/libs/androidfw/include/androidfw/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -213,7 +213,7 @@ inline bool ConfigDescription::operator>(const ConfigDescription& o) const {
inline ::std::ostream& operator<<(::std::ostream& out,
const ConfigDescription& o) {
- return out << o.toString().string();
+ return out << o.toString().c_str();
}
} // namespace android
diff --git a/libs/androidfw/tests/BackupData_test.cpp b/libs/androidfw/tests/BackupData_test.cpp
index e25b616dcbd9..7d3a3411d81d 100644
--- a/libs/androidfw/tests/BackupData_test.cpp
+++ b/libs/androidfw/tests/BackupData_test.cpp
@@ -56,10 +56,10 @@ protected:
mFilename.append(m_external_storage);
mFilename.append(TEST_FILENAME);
- ::unlink(mFilename.string());
- int fd = ::open(mFilename.string(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ ::unlink(mFilename.c_str());
+ int fd = ::open(mFilename.c_str(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
- FAIL() << "Couldn't create " << mFilename.string() << " for writing";
+ FAIL() << "Couldn't create " << mFilename.c_str() << " for writing";
}
mKey1 = String8(KEY1);
mKey2 = String8(KEY2);
@@ -72,7 +72,7 @@ protected:
};
TEST_F(BackupDataTest, WriteAndReadSingle) {
- int fd = ::open(mFilename.string(), O_WRONLY);
+ int fd = ::open(mFilename.c_str(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
EXPECT_EQ(NO_ERROR, writer->WriteEntityHeader(mKey1, sizeof(DATA1)))
@@ -81,7 +81,7 @@ TEST_F(BackupDataTest, WriteAndReadSingle) {
<< "WriteEntityData returned an error";
::close(fd);
- fd = ::open(mFilename.string(), O_RDONLY);
+ fd = ::open(mFilename.c_str(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
EXPECT_EQ(NO_ERROR, reader->Status())
<< "Reader ctor failed";
@@ -114,7 +114,7 @@ TEST_F(BackupDataTest, WriteAndReadSingle) {
}
TEST_F(BackupDataTest, WriteAndReadMultiple) {
- int fd = ::open(mFilename.string(), O_WRONLY);
+ int fd = ::open(mFilename.c_str(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -122,7 +122,7 @@ TEST_F(BackupDataTest, WriteAndReadMultiple) {
writer->WriteEntityData(DATA2, sizeof(DATA2));
::close(fd);
- fd = ::open(mFilename.string(), O_RDONLY);
+ fd = ::open(mFilename.c_str(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -162,7 +162,7 @@ TEST_F(BackupDataTest, WriteAndReadMultiple) {
}
TEST_F(BackupDataTest, SkipEntity) {
- int fd = ::open(mFilename.string(), O_WRONLY);
+ int fd = ::open(mFilename.c_str(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -172,7 +172,7 @@ TEST_F(BackupDataTest, SkipEntity) {
writer->WriteEntityData(DATA3, sizeof(DATA3));
::close(fd);
- fd = ::open(mFilename.string(), O_RDONLY);
+ fd = ::open(mFilename.c_str(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -217,14 +217,14 @@ TEST_F(BackupDataTest, SkipEntity) {
}
TEST_F(BackupDataTest, DeleteEntity) {
- int fd = ::open(mFilename.string(), O_WRONLY);
+ int fd = ::open(mFilename.c_str(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
writer->WriteEntityHeader(mKey2, -1);
::close(fd);
- fd = ::open(mFilename.string(), O_RDONLY);
+ fd = ::open(mFilename.c_str(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -256,7 +256,7 @@ TEST_F(BackupDataTest, DeleteEntity) {
}
TEST_F(BackupDataTest, EneityAfterDelete) {
- int fd = ::open(mFilename.string(), O_WRONLY);
+ int fd = ::open(mFilename.c_str(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -265,7 +265,7 @@ TEST_F(BackupDataTest, EneityAfterDelete) {
writer->WriteEntityData(DATA3, sizeof(DATA3));
::close(fd);
- fd = ::open(mFilename.string(), O_RDONLY);
+ fd = ::open(mFilename.c_str(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -317,7 +317,7 @@ TEST_F(BackupDataTest, EneityAfterDelete) {
}
TEST_F(BackupDataTest, OnlyDeleteEntities) {
- int fd = ::open(mFilename.string(), O_WRONLY);
+ int fd = ::open(mFilename.c_str(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, -1);
writer->WriteEntityHeader(mKey2, -1);
@@ -325,7 +325,7 @@ TEST_F(BackupDataTest, OnlyDeleteEntities) {
writer->WriteEntityHeader(mKey4, -1);
::close(fd);
- fd = ::open(mFilename.string(), O_RDONLY);
+ fd = ::open(mFilename.c_str(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
@@ -385,13 +385,13 @@ TEST_F(BackupDataTest, OnlyDeleteEntities) {
}
TEST_F(BackupDataTest, ReadDeletedEntityData) {
- int fd = ::open(mFilename.string(), O_WRONLY);
+ int fd = ::open(mFilename.c_str(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, -1);
writer->WriteEntityHeader(mKey2, -1);
::close(fd);
- fd = ::open(mFilename.string(), O_RDONLY);
+ fd = ::open(mFilename.c_str(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
diff --git a/libs/androidfw/tests/CommonHelpers.cpp b/libs/androidfw/tests/CommonHelpers.cpp
index 3396729536a4..10138de0843c 100644
--- a/libs/androidfw/tests/CommonHelpers.cpp
+++ b/libs/androidfw/tests/CommonHelpers.cpp
@@ -60,7 +60,7 @@ const std::string& GetTestDataPath() {
std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
auto str = pool->string8ObjectAt(idx);
CHECK(str.has_value()) << "failed to find string entry";
- return std::string(str->string(), str->length());
+ return std::string(str->c_str(), str->length());
}
} // namespace android
diff --git a/libs/androidfw/tests/ConfigDescription_test.cpp b/libs/androidfw/tests/ConfigDescription_test.cpp
index f5c01e5d9b68..ec478b0900ef 100644
--- a/libs/androidfw/tests/ConfigDescription_test.cpp
+++ b/libs/androidfw/tests/ConfigDescription_test.cpp
@@ -50,10 +50,10 @@ TEST(ConfigDescriptionTest, ParseFailWhenQualifiersHaveTrailingDash) {
TEST(ConfigDescriptionTest, ParseBasicQualifiers) {
ConfigDescription config;
EXPECT_TRUE(TestParse("", &config));
- EXPECT_EQ(std::string(""), config.toString().string());
+ EXPECT_EQ(std::string(""), config.toString().c_str());
EXPECT_TRUE(TestParse("fr-land", &config));
- EXPECT_EQ(std::string("fr-land"), config.toString().string());
+ EXPECT_EQ(std::string("fr-land"), config.toString().c_str());
EXPECT_TRUE(
TestParse("mcc310-pl-sw720dp-normal-long-port-night-"
@@ -61,22 +61,22 @@ TEST(ConfigDescriptionTest, ParseBasicQualifiers) {
&config));
EXPECT_EQ(std::string("mcc310-pl-sw720dp-normal-long-port-night-"
"xhdpi-keyssoft-qwerty-navexposed-nonav-v13"),
- config.toString().string());
+ config.toString().c_str());
}
TEST(ConfigDescriptionTest, ParseLocales) {
ConfigDescription config;
EXPECT_TRUE(TestParse("en-rUS", &config));
- EXPECT_EQ(std::string("en-rUS"), config.toString().string());
+ EXPECT_EQ(std::string("en-rUS"), config.toString().c_str());
}
TEST(ConfigDescriptionTest, ParseQualifierAddedInApi13) {
ConfigDescription config;
EXPECT_TRUE(TestParse("sw600dp", &config));
- EXPECT_EQ(std::string("sw600dp-v13"), config.toString().string());
+ EXPECT_EQ(std::string("sw600dp-v13"), config.toString().c_str());
EXPECT_TRUE(TestParse("sw600dp-v8", &config));
- EXPECT_EQ(std::string("sw600dp-v13"), config.toString().string());
+ EXPECT_EQ(std::string("sw600dp-v13"), config.toString().c_str());
}
TEST(ConfigDescriptionTest, ParseCarAttribute) {
@@ -91,13 +91,13 @@ TEST(ConfigDescriptionTest, TestParsingRoundQualifier) {
EXPECT_EQ(android::ResTable_config::SCREENROUND_YES,
config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
EXPECT_EQ(SDK_MARSHMALLOW, config.sdkVersion);
- EXPECT_EQ(std::string("round-v23"), config.toString().string());
+ EXPECT_EQ(std::string("round-v23"), config.toString().c_str());
EXPECT_TRUE(TestParse("notround", &config));
EXPECT_EQ(android::ResTable_config::SCREENROUND_NO,
config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
EXPECT_EQ(SDK_MARSHMALLOW, config.sdkVersion);
- EXPECT_EQ(std::string("notround-v23"), config.toString().string());
+ EXPECT_EQ(std::string("notround-v23"), config.toString().c_str());
}
TEST(ConfigDescriptionTest, TestWideColorGamutQualifier) {
@@ -106,13 +106,13 @@ TEST(ConfigDescriptionTest, TestWideColorGamutQualifier) {
EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_YES,
config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
EXPECT_EQ(SDK_O, config.sdkVersion);
- EXPECT_EQ(std::string("widecg-v26"), config.toString().string());
+ EXPECT_EQ(std::string("widecg-v26"), config.toString().c_str());
EXPECT_TRUE(TestParse("nowidecg", &config));
EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_NO,
config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
EXPECT_EQ(SDK_O, config.sdkVersion);
- EXPECT_EQ(std::string("nowidecg-v26"), config.toString().string());
+ EXPECT_EQ(std::string("nowidecg-v26"), config.toString().c_str());
}
TEST(ConfigDescriptionTest, TestHdrQualifier) {
@@ -121,13 +121,13 @@ TEST(ConfigDescriptionTest, TestHdrQualifier) {
EXPECT_EQ(android::ResTable_config::HDR_YES,
config.colorMode & android::ResTable_config::MASK_HDR);
EXPECT_EQ(SDK_O, config.sdkVersion);
- EXPECT_EQ(std::string("highdr-v26"), config.toString().string());
+ EXPECT_EQ(std::string("highdr-v26"), config.toString().c_str());
EXPECT_TRUE(TestParse("lowdr", &config));
EXPECT_EQ(android::ResTable_config::HDR_NO,
config.colorMode & android::ResTable_config::MASK_HDR);
EXPECT_EQ(SDK_O, config.sdkVersion);
- EXPECT_EQ(std::string("lowdr-v26"), config.toString().string());
+ EXPECT_EQ(std::string("lowdr-v26"), config.toString().c_str());
}
TEST(ConfigDescriptionTest, ParseVrAttribute) {
@@ -135,7 +135,7 @@ TEST(ConfigDescriptionTest, ParseVrAttribute) {
EXPECT_TRUE(TestParse("vrheadset", &config));
EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_VR_HEADSET, config.uiMode);
EXPECT_EQ(SDK_O, config.sdkVersion);
- EXPECT_EQ(std::string("vrheadset-v26"), config.toString().string());
+ EXPECT_EQ(std::string("vrheadset-v26"), config.toString().c_str());
}
static inline ConfigDescription ParseConfigOrDie(android::StringPiece str) {
diff --git a/libs/androidfw/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp
index 115112128636..ba818c4d7645 100644
--- a/libs/androidfw/tests/ObbFile_test.cpp
+++ b/libs/androidfw/tests/ObbFile_test.cpp
@@ -43,9 +43,9 @@ protected:
mFileName.append(externalStorage);
mFileName.append(TEST_FILENAME);
- int fd = ::open(mFileName.string(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ int fd = ::open(mFileName.c_str(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
- FAIL() << "Couldn't create " << mFileName.string() << " for tests";
+ FAIL() << "Couldn't create " << mFileName.c_str() << " for tests";
}
}
@@ -69,17 +69,17 @@ TEST_F(ObbFileTest, WriteThenRead) {
EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE))
<< "Salt should be successfully set";
- EXPECT_TRUE(mObbFile->writeTo(mFileName.string()))
+ EXPECT_TRUE(mObbFile->writeTo(mFileName.c_str()))
<< "couldn't write to fake .obb file";
mObbFile = new ObbFile();
- EXPECT_TRUE(mObbFile->readFrom(mFileName.string()))
+ EXPECT_TRUE(mObbFile->readFrom(mFileName.c_str()))
<< "couldn't read from fake .obb file";
EXPECT_EQ(versionNum, mObbFile->getVersion())
<< "version didn't come out the same as it went in";
- const char* currentPackageName = mObbFile->getPackageName().string();
+ const char* currentPackageName = mObbFile->getPackageName().c_str();
EXPECT_STREQ(packageName, currentPackageName)
<< "package name didn't come out the same as it went in";
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index fbf70981f2de..945981b981a0 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -64,8 +64,8 @@ TEST(ResTableTest, ResourceNameIsResolved) {
String16 defPackage("com.android.basic");
String16 testName("@string/test1");
uint32_t resID =
- table.identifierForName(testName.string(), testName.size(), 0, 0,
- defPackage.string(), defPackage.size());
+ table.identifierForName(testName.c_str(), testName.size(), 0, 0,
+ defPackage.c_str(), defPackage.size());
ASSERT_NE(uint32_t(0x00000000), resID);
ASSERT_EQ(basic::R::string::test1, resID);
}
diff --git a/libs/androidfw/tests/Split_test.cpp b/libs/androidfw/tests/Split_test.cpp
index 2c242dbd3e28..3d88577c078f 100644
--- a/libs/androidfw/tests/Split_test.cpp
+++ b/libs/androidfw/tests/Split_test.cpp
@@ -261,8 +261,8 @@ TEST_F(SplitTest, TestNewResourceIsAccessibleByName) {
const String16 package("com.android.basic");
ASSERT_EQ(
R::string::test3,
- table.identifierForName(name.string(), name.size(), type.string(),
- type.size(), package.string(), package.size()));
+ table.identifierForName(name.c_str(), name.size(), type.c_str(),
+ type.size(), package.c_str(), package.size()));
}
} // namespace
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 10c0a4fc8316..c6f657c5d9a8 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -79,9 +79,9 @@ AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
}
if (String8(expected_str) != *actual_str) {
- return AssertionFailure() << actual_str->string();
+ return AssertionFailure() << actual_str->c_str();
}
- return AssertionSuccess() << actual_str->string();
+ return AssertionSuccess() << actual_str->c_str();
}
} // namespace android
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 7f80dff311f5..ce6b4b74d0da 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -28,6 +28,24 @@ license {
],
}
+aconfig_declarations {
+ name: "hwui_flags",
+ package: "com.android.graphics.hwui.flags",
+ srcs: [
+ "aconfig/hwui_flags.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "hwui_flags_java_lib",
+ aconfig_declarations: "hwui_flags",
+}
+
+cc_aconfig_library {
+ name: "hwui_flags_cc_lib",
+ aconfig_declarations: "hwui_flags",
+}
+
cc_defaults {
name: "hwui_defaults",
defaults: [
@@ -139,6 +157,7 @@ cc_defaults {
"libstatspull_lazy",
"libstatssocket_lazy",
"libtonemap",
+ "hwui_flags_cc_lib",
],
},
host: {
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
new file mode 100644
index 000000000000..d074a90d1adf
--- /dev/null
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.graphics.hwui.flags"
+
+flag {
+ name: "limited_hdr"
+ namespace: "core_graphics"
+ description: "API to enable apps to restrict the amount of HDR headroom that is used"
+ bug: "234181960"
+} \ No newline at end of file
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index 8baa4b770f85..eab888ef4d1a 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -31,15 +31,11 @@
#include <utils/Log.h>
#include <utils/Macros.h>
-// The ideal size of a page allocation (these need to be multiples of 8)
-#define INITIAL_PAGE_SIZE ((size_t)512) // 512b
-#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
-
// The maximum amount of wasted space we can have per page
// Allocations exceeding this will have their own dedicated page
// If this is too low, we will malloc too much
// Too high, and we may waste too much space
-// Must be smaller than INITIAL_PAGE_SIZE
+// Must be smaller than kInitialPageSize
#define MAX_WASTE_RATIO (0.5f)
#if LOG_NDEBUG
@@ -75,6 +71,10 @@ static void _addAllocation(int count) {
namespace android {
namespace uirenderer {
+// The ideal size of a page allocation (these need to be multiples of 8)
+static constexpr size_t kInitialPageSize = 512; // 512b
+static constexpr size_t kMaxPageSize = 131072; // 128kb
+
class LinearAllocator::Page {
public:
Page* next() { return mNextPage; }
@@ -94,8 +94,8 @@ private:
};
LinearAllocator::LinearAllocator()
- : mPageSize(INITIAL_PAGE_SIZE)
- , mMaxAllocSize(INITIAL_PAGE_SIZE * MAX_WASTE_RATIO)
+ : mPageSize(kInitialPageSize)
+ , mMaxAllocSize(kInitialPageSize * MAX_WASTE_RATIO)
, mNext(0)
, mCurrentPage(0)
, mPages(0)
@@ -135,8 +135,8 @@ bool LinearAllocator::fitsInCurrentPage(size_t size) {
void LinearAllocator::ensureNext(size_t size) {
if (fitsInCurrentPage(size)) return;
- if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
- mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
+ if (mCurrentPage && mPageSize < kMaxPageSize) {
+ mPageSize = min(kMaxPageSize, mPageSize * 2);
mMaxAllocSize = mPageSize * MAX_WASTE_RATIO;
mPageSize = ALIGN(mPageSize);
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 6c0fd5f65359..5ce990fdeb82 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -23,6 +23,12 @@ package {
cc_library_shared {
name: "libinputservice",
+ defaults: [
+ // Build using the same flags and configurations as inputflinger.
+ "inputflinger_defaults",
+ ],
+ host_supported: false,
+
srcs: [
"PointerController.cpp",
"PointerControllerContext.cpp",
@@ -50,12 +56,4 @@ cc_library_shared {
],
include_dirs: ["frameworks/native/services"],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wthread-safety",
- ],
-
}
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index c3ad7670d473..6a465442c2b4 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -47,7 +47,7 @@ MouseCursorController::MouseCursorController(PointerControllerContext& context)
mLocked.pointerX = 0;
mLocked.pointerY = 0;
mLocked.pointerAlpha = 0.0f; // pointer is initially faded
- mLocked.pointerSprite = mContext.getSpriteController()->createSprite();
+ mLocked.pointerSprite = mContext.getSpriteController().createSprite();
mLocked.updatePointerIcon = false;
mLocked.requestedPointerType = PointerIconStyle::TYPE_NOT_SPECIFIED;
mLocked.resolvedPointerType = PointerIconStyle::TYPE_NOT_SPECIFIED;
@@ -325,8 +325,8 @@ bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(
}
if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) {
- sp<SpriteController> spriteController = mContext.getSpriteController();
- spriteController->openTransaction();
+ auto& spriteController = mContext.getSpriteController();
+ spriteController.openTransaction();
int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame;
mLocked.animationFrameIndex += incr;
@@ -336,7 +336,7 @@ bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(
}
mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]);
- spriteController->closeTransaction();
+ spriteController.closeTransaction();
}
// Keep animating.
return true;
@@ -346,8 +346,8 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) {
if (!mLocked.viewport.isValid()) {
return;
}
- sp<SpriteController> spriteController = mContext.getSpriteController();
- spriteController->openTransaction();
+ auto& spriteController = mContext.getSpriteController();
+ spriteController.openTransaction();
mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
@@ -392,7 +392,7 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) {
mLocked.updatePointerIcon = false;
}
- spriteController->closeTransaction();
+ spriteController.closeTransaction();
}
void MouseCursorController::loadResourcesLocked(bool getAdditionalMouseResources) REQUIRES(mLock) {
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index e21d6fb2fe14..435452c11370 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -63,7 +63,7 @@ void PointerController::DisplayInfoListener::onPointerControllerDestroyed() {
std::shared_ptr<PointerController> PointerController::create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- const sp<SpriteController>& spriteController) {
+ SpriteController& spriteController) {
// using 'new' to access non-public constructor
std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
new PointerController(policy, looper, spriteController));
@@ -85,8 +85,7 @@ std::shared_ptr<PointerController> PointerController::create(
}
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper,
- const sp<SpriteController>& spriteController)
+ const sp<Looper>& looper, SpriteController& spriteController)
: PointerController(
policy, looper, spriteController,
[](const sp<android::gui::WindowInfosListener>& listener) {
@@ -97,13 +96,12 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
}) {}
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper,
- const sp<SpriteController>& spriteController,
+ const sp<Looper>& looper, SpriteController& spriteController,
WindowListenerConsumer registerListener,
WindowListenerConsumer unregisterListener)
: mContext(policy, looper, spriteController, *this),
mCursorController(mContext),
- mDisplayInfoListener(new DisplayInfoListener(this)),
+ mDisplayInfoListener(sp<DisplayInfoListener>::make(this)),
mUnregisterWindowInfosListener(std::move(unregisterListener)) {
std::scoped_lock lock(getLock());
mLocked.presentation = Presentation::SPOT;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 62ee74331302..c7e772d79dc4 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -47,7 +47,7 @@ class PointerController : public PointerControllerInterface {
public:
static std::shared_ptr<PointerController> create(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- const sp<SpriteController>& spriteController);
+ SpriteController& spriteController);
~PointerController() override;
@@ -83,13 +83,12 @@ protected:
// Constructor used to test WindowInfosListener registration.
PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- const sp<SpriteController>& spriteController,
- WindowListenerConsumer registerListener,
+ SpriteController& spriteController, WindowListenerConsumer registerListener,
WindowListenerConsumer unregisterListener);
private:
PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- const sp<SpriteController>& spriteController);
+ SpriteController& spriteController);
friend PointerControllerContext::LooperCallback;
friend PointerControllerContext::MessageHandler;
diff --git a/libs/input/PointerControllerContext.cpp b/libs/input/PointerControllerContext.cpp
index f30e8d8e33a5..15c35176afce 100644
--- a/libs/input/PointerControllerContext.cpp
+++ b/libs/input/PointerControllerContext.cpp
@@ -32,12 +32,12 @@ namespace android {
PointerControllerContext::PointerControllerContext(
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- const sp<SpriteController>& spriteController, PointerController& controller)
+ SpriteController& spriteController, PointerController& controller)
: mPolicy(policy),
mLooper(looper),
mSpriteController(spriteController),
- mHandler(new MessageHandler()),
- mCallback(new LooperCallback()),
+ mHandler(sp<MessageHandler>::make()),
+ mCallback(sp<LooperCallback>::make()),
mController(controller),
mAnimator(*this) {
std::scoped_lock lock(mLock);
@@ -93,7 +93,7 @@ sp<PointerControllerPolicyInterface> PointerControllerContext::getPolicy() {
return mPolicy;
}
-sp<SpriteController> PointerControllerContext::getSpriteController() {
+SpriteController& PointerControllerContext::getSpriteController() {
return mSpriteController;
}
diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h
index f6f5d3bc51bd..98c3988e7df4 100644
--- a/libs/input/PointerControllerContext.h
+++ b/libs/input/PointerControllerContext.h
@@ -92,7 +92,7 @@ public:
class PointerControllerContext {
public:
PointerControllerContext(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, const sp<SpriteController>& spriteController,
+ const sp<Looper>& looper, SpriteController& spriteController,
PointerController& controller);
~PointerControllerContext();
@@ -109,7 +109,7 @@ public:
void setCallbackController(std::shared_ptr<PointerController> controller);
sp<PointerControllerPolicyInterface> getPolicy();
- sp<SpriteController> getSpriteController();
+ SpriteController& getSpriteController();
void handleDisplayEvents();
@@ -163,7 +163,7 @@ private:
sp<PointerControllerPolicyInterface> mPolicy;
sp<Looper> mLooper;
- sp<SpriteController> mSpriteController;
+ SpriteController& mSpriteController;
sp<MessageHandler> mHandler;
sp<LooperCallback> mCallback;
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index 130b204954b4..6dc45a6aebec 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -31,12 +31,19 @@ SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLaye
ParentSurfaceProvider parentSurfaceProvider)
: mLooper(looper),
mOverlayLayer(overlayLayer),
+ mHandler(sp<Handler>::make()),
mParentSurfaceProvider(std::move(parentSurfaceProvider)) {
- mHandler = new WeakMessageHandler(this);
mLocked.transactionNestingCount = 0;
mLocked.deferredSpriteUpdate = false;
}
+void SpriteController::setHandlerController(
+ const std::shared_ptr<android::SpriteController>& controller) {
+ // Initialize the weak message handler outside the constructor, because we cannot get a shared
+ // pointer to self in the constructor.
+ mHandler->spriteController = controller;
+}
+
SpriteController::~SpriteController() {
mLooper->removeMessages(mHandler);
@@ -47,7 +54,7 @@ SpriteController::~SpriteController() {
}
sp<Sprite> SpriteController::createSprite() {
- return new SpriteImpl(this);
+ return sp<SpriteImpl>::make(*this);
}
void SpriteController::openTransaction() {
@@ -65,7 +72,7 @@ void SpriteController::closeTransaction() {
mLocked.transactionNestingCount -= 1;
if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) {
mLocked.deferredSpriteUpdate = false;
- mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
+ mLooper->sendMessage(mHandler, Message(Handler::MSG_UPDATE_SPRITES));
}
}
@@ -76,7 +83,7 @@ void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
if (mLocked.transactionNestingCount != 0) {
mLocked.deferredSpriteUpdate = true;
} else {
- mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
+ mLooper->sendMessage(mHandler, Message(Handler::MSG_UPDATE_SPRITES));
}
}
}
@@ -85,18 +92,7 @@ void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceCon
bool wasEmpty = mLocked.disposedSurfaces.empty();
mLocked.disposedSurfaces.push_back(surfaceControl);
if (wasEmpty) {
- mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
- }
-}
-
-void SpriteController::handleMessage(const Message& message) {
- switch (message.what) {
- case MSG_UPDATE_SPRITES:
- doUpdateSprites();
- break;
- case MSG_DISPOSE_SURFACES:
- doDisposeSurfaces();
- break;
+ mLooper->sendMessage(mHandler, Message(Handler::MSG_DISPOSE_SURFACES));
}
}
@@ -327,7 +323,7 @@ void SpriteController::doDisposeSurfaces() {
void SpriteController::ensureSurfaceComposerClient() {
if (mSurfaceComposerClient == NULL) {
- mSurfaceComposerClient = new SurfaceComposerClient();
+ mSurfaceComposerClient = sp<SurfaceComposerClient>::make();
}
}
@@ -353,25 +349,41 @@ sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height
return surfaceControl;
}
-// --- SpriteController::SpriteImpl ---
+// --- SpriteController::Handler ---
-SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
- mController(controller) {
+void SpriteController::Handler::handleMessage(const android::Message& message) {
+ auto controller = spriteController.lock();
+ if (!controller) {
+ return;
+ }
+
+ switch (message.what) {
+ case MSG_UPDATE_SPRITES:
+ controller->doUpdateSprites();
+ break;
+ case MSG_DISPOSE_SURFACES:
+ controller->doDisposeSurfaces();
+ break;
+ }
}
+// --- SpriteController::SpriteImpl ---
+
+SpriteController::SpriteImpl::SpriteImpl(SpriteController& controller) : mController(controller) {}
+
SpriteController::SpriteImpl::~SpriteImpl() {
- AutoMutex _m(mController->mLock);
+ AutoMutex _m(mController.mLock);
// Let the controller take care of deleting the last reference to sprite
// surfaces so that we do not block the caller on an IPC here.
if (mLocked.state.surfaceControl != NULL) {
- mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
+ mController.disposeSurfaceLocked(mLocked.state.surfaceControl);
mLocked.state.surfaceControl.clear();
}
}
void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
- AutoMutex _l(mController->mLock);
+ AutoMutex _l(mController.mLock);
uint32_t dirty;
if (icon.isValid()) {
@@ -401,7 +413,7 @@ void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
}
void SpriteController::SpriteImpl::setVisible(bool visible) {
- AutoMutex _l(mController->mLock);
+ AutoMutex _l(mController.mLock);
if (mLocked.state.visible != visible) {
mLocked.state.visible = visible;
@@ -410,7 +422,7 @@ void SpriteController::SpriteImpl::setVisible(bool visible) {
}
void SpriteController::SpriteImpl::setPosition(float x, float y) {
- AutoMutex _l(mController->mLock);
+ AutoMutex _l(mController.mLock);
if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
mLocked.state.positionX = x;
@@ -420,7 +432,7 @@ void SpriteController::SpriteImpl::setPosition(float x, float y) {
}
void SpriteController::SpriteImpl::setLayer(int32_t layer) {
- AutoMutex _l(mController->mLock);
+ AutoMutex _l(mController.mLock);
if (mLocked.state.layer != layer) {
mLocked.state.layer = layer;
@@ -429,7 +441,7 @@ void SpriteController::SpriteImpl::setLayer(int32_t layer) {
}
void SpriteController::SpriteImpl::setAlpha(float alpha) {
- AutoMutex _l(mController->mLock);
+ AutoMutex _l(mController.mLock);
if (mLocked.state.alpha != alpha) {
mLocked.state.alpha = alpha;
@@ -439,7 +451,7 @@ void SpriteController::SpriteImpl::setAlpha(float alpha) {
void SpriteController::SpriteImpl::setTransformationMatrix(
const SpriteTransformationMatrix& matrix) {
- AutoMutex _l(mController->mLock);
+ AutoMutex _l(mController.mLock);
if (mLocked.state.transformationMatrix != matrix) {
mLocked.state.transformationMatrix = matrix;
@@ -448,7 +460,7 @@ void SpriteController::SpriteImpl::setTransformationMatrix(
}
void SpriteController::SpriteImpl::setDisplayId(int32_t displayId) {
- AutoMutex _l(mController->mLock);
+ AutoMutex _l(mController.mLock);
if (mLocked.state.displayId != displayId) {
mLocked.state.displayId = displayId;
@@ -461,7 +473,7 @@ void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
mLocked.state.dirty |= dirty;
if (!wasDirty) {
- mController->invalidateSpriteLocked(this);
+ mController.invalidateSpriteLocked(sp<SpriteImpl>::fromExisting(this));
}
}
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 1f113c045360..04ecb3895aa2 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -109,15 +109,19 @@ public:
*
* Clients are responsible for animating sprites by periodically updating their properties.
*/
-class SpriteController : public MessageHandler {
-protected:
- virtual ~SpriteController();
-
+class SpriteController {
public:
using ParentSurfaceProvider = std::function<sp<SurfaceControl>(int /*displayId*/)>;
SpriteController(const sp<Looper>& looper, int32_t overlayLayer, ParentSurfaceProvider parent);
+ SpriteController(const SpriteController&) = delete;
+ SpriteController& operator=(const SpriteController&) = delete;
+ virtual ~SpriteController();
- /* Creates a new sprite, initially invisible. */
+ /* Initialize the callback for the message handler. */
+ void setHandlerController(const std::shared_ptr<SpriteController>& controller);
+
+ /* Creates a new sprite, initially invisible. The lifecycle of the sprite must not extend beyond
+ * the lifecycle of this SpriteController. */
virtual sp<Sprite> createSprite();
/* Opens or closes a transaction to perform a batch of sprite updates as part of
@@ -129,9 +133,12 @@ public:
virtual void closeTransaction();
private:
- enum {
- MSG_UPDATE_SPRITES,
- MSG_DISPOSE_SURFACES,
+ class Handler : public virtual android::MessageHandler {
+ public:
+ enum { MSG_UPDATE_SPRITES, MSG_DISPOSE_SURFACES };
+
+ void handleMessage(const Message& message) override;
+ std::weak_ptr<SpriteController> spriteController;
};
enum {
@@ -192,7 +199,7 @@ private:
virtual ~SpriteImpl();
public:
- explicit SpriteImpl(const sp<SpriteController> controller);
+ explicit SpriteImpl(SpriteController& controller);
virtual void setIcon(const SpriteIcon& icon);
virtual void setVisible(bool visible);
@@ -220,7 +227,7 @@ private:
}
private:
- sp<SpriteController> mController;
+ SpriteController& mController;
struct Locked {
SpriteState state;
@@ -245,7 +252,7 @@ private:
sp<Looper> mLooper;
const int32_t mOverlayLayer;
- sp<WeakMessageHandler> mHandler;
+ sp<Handler> mHandler;
ParentSurfaceProvider mParentSurfaceProvider;
sp<SurfaceComposerClient> mSurfaceComposerClient;
@@ -260,7 +267,6 @@ private:
void invalidateSpriteLocked(const sp<SpriteImpl>& sprite);
void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl);
- void handleMessage(const Message& message);
void doUpdateSprites();
void doDisposeSurfaces();
diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp
index d9fe5996bcff..b8de919fbd8c 100644
--- a/libs/input/TouchSpotController.cpp
+++ b/libs/input/TouchSpotController.cpp
@@ -39,15 +39,15 @@ namespace android {
// --- Spot ---
-void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
+void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float newX, float newY,
int32_t displayId) {
sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
sprite->setAlpha(alpha);
sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
- sprite->setPosition(x, y);
+ sprite->setPosition(newX, newY);
sprite->setDisplayId(displayId);
- this->x = x;
- this->y = y;
+ x = newX;
+ y = newY;
if (icon != mLastIcon) {
mLastIcon = icon;
@@ -98,8 +98,8 @@ void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32
#endif
std::scoped_lock lock(mLock);
- sp<SpriteController> spriteController = mContext.getSpriteController();
- spriteController->openTransaction();
+ auto& spriteController = mContext.getSpriteController();
+ spriteController.openTransaction();
// Add or move spots for fingers that are down.
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
@@ -125,7 +125,7 @@ void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32
}
}
- spriteController->closeTransaction();
+ spriteController.closeTransaction();
}
void TouchSpotController::clearSpots() {
@@ -167,7 +167,7 @@ TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t
sprite = mLocked.recycledSprites.back();
mLocked.recycledSprites.pop_back();
} else {
- sprite = mContext.getSpriteController()->createSprite();
+ sprite = mContext.getSpriteController().createSprite();
}
// Return the new spot.
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 85747514aa03..3e2e43fdfdca 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -157,7 +157,7 @@ protected:
sp<MockSprite> mPointerSprite;
sp<MockPointerControllerPolicyInterface> mPolicy;
- sp<MockSpriteController> mSpriteController;
+ std::unique_ptr<MockSpriteController> mSpriteController;
std::shared_ptr<PointerController> mPointerController;
private:
@@ -175,14 +175,13 @@ private:
PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<MockSprite>),
mLooper(new MyLooper), mThread(&PointerControllerTest::loopThread, this) {
-
- mSpriteController = new NiceMock<MockSpriteController>(mLooper);
+ mSpriteController.reset(new NiceMock<MockSpriteController>(mLooper));
mPolicy = new MockPointerControllerPolicyInterface();
EXPECT_CALL(*mSpriteController, createSprite())
.WillOnce(Return(mPointerSprite));
- mPointerController = PointerController::create(mPolicy, mLooper, mSpriteController);
+ mPointerController = PointerController::create(mPolicy, mLooper, *mSpriteController);
}
PointerControllerTest::~PointerControllerTest() {
@@ -319,10 +318,9 @@ class PointerControllerWindowInfoListenerTest : public Test {};
class TestPointerController : public PointerController {
public:
TestPointerController(sp<android::gui::WindowInfosListener>& registeredListener,
- const sp<Looper>& looper)
+ const sp<Looper>& looper, SpriteController& spriteController)
: PointerController(
- new MockPointerControllerPolicyInterface(), looper,
- new NiceMock<MockSpriteController>(looper),
+ new MockPointerControllerPolicyInterface(), looper, spriteController,
[&registeredListener](const sp<android::gui::WindowInfosListener>& listener) {
// Register listener
registeredListener = listener;
@@ -335,10 +333,12 @@ public:
TEST_F(PointerControllerWindowInfoListenerTest,
doesNotCrashIfListenerCalledAfterPointerControllerDestroyed) {
+ sp<Looper> looper = new Looper(false);
+ auto spriteController = NiceMock<MockSpriteController>(looper);
sp<android::gui::WindowInfosListener> registeredListener;
sp<android::gui::WindowInfosListener> localListenerCopy;
{
- TestPointerController pointerController(registeredListener, new Looper(false));
+ TestPointerController pointerController(registeredListener, looper, spriteController);
ASSERT_NE(nullptr, registeredListener) << "WindowInfosListener was not registered";
localListenerCopy = registeredListener;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c3087bc1c0d2..e2f407294458 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4739,6 +4739,97 @@ public class AudioManager {
/**
* @hide
+ * Test method to return the list of UIDs currently marked as ducked because of their
+ * audio focus status
+ * @return the list of UIDs, can be empty when no app is being ducked.
+ */
+ @TestApi
+ @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
+ public @NonNull List<Integer> getFocusDuckedUidsForTest() {
+ try {
+ return getService().getFocusDuckedUidsForTest();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Test method to return the duration of the fade out applied on the players of a focus loser
+ * @return the fade out duration in ms
+ */
+ @TestApi
+ @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
+ public long getFocusFadeOutDurationForTest() {
+ try {
+ return getService().getFocusFadeOutDurationForTest();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Test method to return the length of time after a fade-out before the focus loser is unmuted
+ * (and is faded back in).
+ * @return the time gap after a fade-out completion on focus loss, and fade-in start in ms.
+ */
+ @TestApi
+ @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
+ public long getFocusUnmuteDelayAfterFadeOutForTest() {
+ try {
+ return getService().getFocusUnmuteDelayAfterFadeOutForTest();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Test method to start preventing applications from requesting audio focus during a test,
+ * which could interfere with the functionality/behavior under test.
+ * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest}
+ * when the testing is done. If this is not the case (e.g. in case of a test crash),
+ * a death observer mechanism will ensure the system is not left in a bad state, but this should
+ * not be relied on when implementing tests.
+ * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance
+ * be those of the test runner and other players used in the test, or the "fake" UIDs used
+ * for testing with {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}.
+ * @return true if the focus freeze mode is successfully entered, false if there was an issue,
+ * such as another freeze in place at the time of invocation.
+ * A false result should result in a test failure as this would indicate the system is not
+ * in a proper state with a predictable behavior for audio focus management.
+ */
+ @TestApi
+ @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ public boolean enterAudioFocusFreezeForTest(@NonNull List<Integer> exemptedUids) {
+ Objects.requireNonNull(exemptedUids);
+ try {
+ final int[] uids = exemptedUids.stream().mapToInt(Integer::intValue).toArray();
+ return getService().enterAudioFocusFreezeForTest(mICallBack, uids);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Test method to end preventing applications from requesting audio focus during a test.
+ * @return true if the focus freeze mode is successfully exited, false if there was an issue,
+ * such as the freeze already having ended, or not started.
+ */
+ @TestApi
+ @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ public boolean exitAudioFocusFreezeForTest() {
+ try {
+ return getService().exitAudioFocusFreezeForTest(mICallBack);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
* Request or lock audio focus.
* This method is to be used by system components that have registered an
* {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5cbb4e539d0a..e45ef404995c 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -529,6 +529,23 @@ interface IAudioService {
long getFadeOutDurationOnFocusLossMillis(in AudioAttributes aa);
+ @EnforcePermission("QUERY_AUDIO_STATE")
+ /* Returns a List<Integer> */
+ @SuppressWarnings(value = {"untyped-collection"})
+ List getFocusDuckedUidsForTest();
+
+ @EnforcePermission("QUERY_AUDIO_STATE")
+ long getFocusFadeOutDurationForTest();
+
+ @EnforcePermission("QUERY_AUDIO_STATE")
+ long getFocusUnmuteDelayAfterFadeOutForTest();
+
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ boolean enterAudioFocusFreezeForTest(IBinder cb, in int[] uids);
+
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ boolean exitAudioFocusFreezeForTest(IBinder cb);
+
void registerModeDispatcher(IAudioModeDispatcher dispatcher);
oneway void unregisterModeDispatcher(IAudioModeDispatcher dispatcher);
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index 304eecb9701a..d294601b44cc 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -108,6 +108,7 @@ interface IMediaProjectionManager {
+ ".permission.MANAGE_MEDIA_PROJECTION)")
void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible);
+ @EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
void addCallback(IMediaProjectionWatcherCallback callback);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 0d9bd6536700..371b47fe3421 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -617,7 +617,7 @@ public final class MediaSessionManager {
mService.dispatchMediaKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
needWakeLock);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to send key event.", e);
+ e.rethrowFromSystemServer();
}
}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index ac8e4d45f485..8ed4bf2b9cc3 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -920,7 +920,7 @@ public class MediaRouter2ManagerTest {
CountDownLatch addedLatch = new CountDownLatch(1);
CountDownLatch preferenceLatch = new CountDownLatch(1);
- // A dummy callback is required to send route feature info.
+ // A placeholder callback is required to send route feature info.
RouteCallback routeCallback = new RouteCallback() {};
MediaRouter2Manager.Callback managerCallback =
new MediaRouter2Manager.Callback() {
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index c25df6e08fd0..c571b742d2d1 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -144,6 +144,8 @@ APerformanceHintSession* APerformanceHintManager::createSession(
binder::Status ret =
mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
if (!ret.isOk() || !session) {
+ ALOGE("%s: PerformanceHint cannot create hint session. %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
return nullptr;
}
return new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index d778febe9faf..d6b7ecf5819d 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -208,3 +208,22 @@ android_app {
],
min_sdk_version: "24",
}
+
+//##########################################################
+// Variant: Add apk to an apex
+android_app {
+ name: "CtsShimAddApkToApex",
+ sdk_version: "current",
+ srcs: ["shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java"],
+ optimize: {
+ enabled: false,
+ },
+ dex_preopt: {
+ enabled: false,
+ },
+ manifest: "shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.apex.cts.shim.v2_add_apk_to_apex",
+ ],
+}
diff --git a/packages/CtsShim/build/shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml b/packages/CtsShim/build/shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml
new file mode 100644
index 000000000000..0e620b062ed6
--- /dev/null
+++ b/packages/CtsShim/build/shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.addapktoapex.app">
+
+ <application>
+ <activity android:name=".AddApkToApexDeviceActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt b/packages/CtsShim/build/shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java
index 9c1bcec2f396..c68904b30d6a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt
+++ b/packages/CtsShim/build/shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java
@@ -12,23 +12,31 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
-package com.android.systemui.biometrics.ui.binder
+package android.addapktoapex.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
-import com.android.systemui.biometrics.AuthBiometricFingerprintView
-import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel
+/**
+ * A simple activity which logs to Logcat.
+ */
+public class AddApkToApexDeviceActivity extends Activity {
-object AuthBiometricFingerprintViewBinder {
+ private static final String TAG = AddApkToApexDeviceActivity.class.getSimpleName();
/**
- * Binds a [AuthBiometricFingerprintView.mIconView] to a [AuthBiometricFingerprintViewModel].
+ * The test string to log.
*/
- @JvmStatic
- fun bind(view: AuthBiometricFingerprintView, viewModel: AuthBiometricFingerprintViewModel) {
- if (view.isSfps) {
- AuthBiometricFingerprintIconViewBinder.bind(view.getIconView(), viewModel)
- }
+ private static final String TEST_STRING = "AddApkToApexTestString";
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ // Log the test string to Logcat.
+ Log.i(TAG, TEST_STRING);
}
+
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index df91d98b8360..80e876196f7f 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -443,7 +443,7 @@ public class PackageInstallerActivity extends AlertActivity {
if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);
if (mAppSnippet != null) {
- // load dummy layout with OK button disabled until we override this layout in
+ // load placeholder layout with OK button disabled until we override this layout in
// startInstallConfirm
bindUi();
checkIfAllowedAndInitiateInstall();
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
index 3f7cc199aed8..b6500340be25 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
@@ -21,7 +21,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.snapshotFlow
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@@ -29,7 +28,6 @@ import kotlinx.coroutines.flow.filter
/**
* An action when run, hides the keyboard if it's open.
*/
-@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun hideKeyboardAction(): () -> Unit {
val keyboardController = LocalSoftwareKeyboardController.current
@@ -41,7 +39,6 @@ fun hideKeyboardAction(): () -> Unit {
*
* And when user scrolling the lazy list, hides the keyboard if it's open.
*/
-@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun rememberLazyListStateAndHideKeyboardWhenStartScroll(): LazyListState {
val listState = rememberLazyListState()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt
index 944ef7fa33fb..e9b3109eefdd 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt
@@ -21,7 +21,6 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Text
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.SoftwareKeyboardController
@@ -32,12 +31,11 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
-@OptIn(ExperimentalComposeUiApi::class)
@RunWith(AndroidJUnit4::class)
class KeyboardsTest {
@get:Rule
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsThemeTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsThemeTest.kt
index 2ff3039eb197..bd8a54bfa4a3 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsThemeTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsThemeTest.kt
@@ -31,10 +31,10 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.anyInt
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
-import org.mockito.Mockito.`when` as whenever
+import org.mockito.kotlin.any
+import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class SettingsThemeTest {
@@ -55,7 +55,7 @@ class SettingsThemeTest {
@Before
fun setUp() {
whenever(context.resources).thenReturn(resources)
- whenever(resources.getString(anyInt())).thenReturn("")
+ whenever(resources.getString(any())).thenReturn("")
}
private fun mockAndroidConfig(configName: String, configValue: String) {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedTextTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedTextTest.kt
index 2c218e3050e0..5e596201128b 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedTextTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedTextTest.kt
@@ -32,9 +32,9 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
class AnnotatedTextTest {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt
index 872d957a6a24..3e8fdecca810 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt
@@ -33,9 +33,9 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
class SettingsScaffoldTest {
diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp
index 65f5d34bd8d1..4031cd7f7a6f 100644
--- a/packages/SettingsLib/Spa/testutils/Android.bp
+++ b/packages/SettingsLib/Spa/testutils/Android.bp
@@ -30,7 +30,7 @@ android_library {
"androidx.compose.ui_ui-test-junit4",
"androidx.compose.ui_ui-test-manifest",
"androidx.lifecycle_lifecycle-runtime-testing",
- "mockito",
+ "mockito-kotlin2",
"truth-prebuilt",
],
kotlincflags: [
diff --git a/packages/SettingsLib/Spa/testutils/build.gradle.kts b/packages/SettingsLib/Spa/testutils/build.gradle.kts
index f5a22c9fbb5d..50243dcd8c9b 100644
--- a/packages/SettingsLib/Spa/testutils/build.gradle.kts
+++ b/packages/SettingsLib/Spa/testutils/build.gradle.kts
@@ -41,7 +41,12 @@ dependencies {
api("androidx.arch.core:core-testing:2.2.0-alpha01")
api("androidx.compose.ui:ui-test-junit4:$jetpackComposeVersion")
api("androidx.lifecycle:lifecycle-runtime-testing")
+ api("org.mockito.kotlin:mockito-kotlin:5.1.0")
+ api("org.mockito:mockito-core") {
+ version {
+ strictly("2.28.2")
+ }
+ }
api(libs.truth)
- api("org.mockito:mockito-core:2.21.0")
debugApi("androidx.compose.ui:ui-test-manifest:$jetpackComposeVersion")
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java
index 745591235dbb..4fcdc8b24357 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java
@@ -27,6 +27,7 @@ import androidx.preference.PreferenceScreen;
import com.android.settingslib.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.utils.ThreadUtils;
/**
* Preference controller for bluetooth address
@@ -74,13 +75,18 @@ public abstract class AbstractBluetoothAddressPreferenceController
protected void updateConnectivity() {
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
if (bluetooth != null && mBtAddress != null) {
- String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null;
- if (!TextUtils.isEmpty(address)) {
- // Convert the address to lowercase for consistency with the wifi MAC address.
- mBtAddress.setSummary(address.toLowerCase());
- } else {
- mBtAddress.setSummary(R.string.status_unavailable);
- }
+ ThreadUtils.postOnBackgroundThread(() -> {
+ String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null;
+ ThreadUtils.postOnMainThread(() -> {
+ if (!TextUtils.isEmpty(address)) {
+ // Convert the address to lowercase for consistency with the wifi MAC
+ // address.
+ mBtAddress.setSummary(address.toLowerCase());
+ } else {
+ mBtAddress.setSummary(R.string.status_unavailable);
+ }
+ });
+ });
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/dpp/WifiDppIntentHelper.java b/packages/SettingsLib/src/com/android/settingslib/wifi/dpp/WifiDppIntentHelper.java
index 1134d13132e8..bc8c56087a7b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/dpp/WifiDppIntentHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/dpp/WifiDppIntentHelper.java
@@ -28,6 +28,11 @@ import java.util.List;
* Wifi dpp intent helper functions to share between the Settings App and SystemUI.
*/
public class WifiDppIntentHelper {
+ /**
+ * Action added to the intent when app wants to launch the QR code generator with lock screen.
+ */
+ public static final String ACTION_CONFIGURATOR_AUTH_QR_CODE_GENERATOR =
+ "android.settings.WIFI_DPP_CONFIGURATOR_AUTH_QR_CODE_GENERATOR";
static final String EXTRA_WIFI_SECURITY = "security";
/** The data corresponding to {@code WifiConfiguration} SSID */
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index 5c55a435b463..c037c400948f 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -42,7 +42,10 @@ android_robolectric_test {
name: "SettingsLibRoboTests",
srcs: ["src/**/*.java"],
static_libs: [
+ "Settings_robolectric_meta_service_file",
+ "Robolectric_shadows_androidx_fragment_upstream",
"SettingsLib-robo-testutils",
+ "androidx.fragment_fragment",
"androidx.test.core",
"androidx.core_core",
"testng", // TODO: remove once JUnit on Android provides assertThrows
@@ -53,6 +56,20 @@ android_robolectric_test {
test_options: {
timeout: 36000,
},
+ upstream: true,
+}
+
+java_genrule {
+ name: "Settings_robolectric_meta_service_file",
+ out: ["robolectric_meta_service_file.jar"],
+ tools: ["soong_zip"],
+ cmd: "mkdir -p $(genDir)/META-INF/services/ && touch $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider &&" +
+ "echo -e 'org.robolectric.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "echo -e 'org.robolectric.shadows.multidex.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "echo -e 'org.robolectric.shadows.httpclient.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ //"echo -e 'com.android.settings.testutils.shadow.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "echo -e 'com.android.settingslib.testutils.shadow.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
+ "$(location soong_zip) -o $(out) -C $(genDir) -D $(genDir)/META-INF/services/",
}
java_library {
@@ -60,9 +77,23 @@ java_library {
srcs: [
"testutils/com/android/settingslib/testutils/**/*.java",
],
-
+ javacflags: [
+ "-Aorg.robolectric.annotation.processing.shadowPackage=com.android.settingslib.testutils.shadow",
+ "-Aorg.robolectric.annotation.processing.sdkCheckMode=ERROR",
+ // Uncomment the below to debug annotation processors not firing.
+ //"-verbose",
+ //"-XprintRounds",
+ //"-XprintProcessorInfo",
+ //"-Xlint",
+ //"-J-verbose",
+ ],
+ plugins: [
+ "auto_value_plugin_1.9",
+ "auto_value_builder_plugin_1.9",
+ "Robolectric_processor_upstream",
+ ],
libs: [
- "Robolectric_all-target",
+ "Robolectric_all-target_upstream",
"mockito-robolectric-prebuilt",
"truth-prebuilt",
],
diff --git a/packages/SettingsLib/tests/robotests/config/robolectric.properties b/packages/SettingsLib/tests/robotests/config/robolectric.properties
index fab7251d020b..2a9e50df62b0 100644
--- a/packages/SettingsLib/tests/robotests/config/robolectric.properties
+++ b/packages/SettingsLib/tests/robotests/config/robolectric.properties
@@ -1 +1,2 @@
sdk=NEWEST_SDK
+instrumentedPackages=androidx.preference
diff --git a/packages/SettingsLib/tests/robotests/fragment/Android.bp b/packages/SettingsLib/tests/robotests/fragment/Android.bp
new file mode 100644
index 000000000000..3e67156af0c4
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/Android.bp
@@ -0,0 +1,40 @@
+//#############################################
+// Compile Robolectric shadows framework misapplied to androidx
+//#############################################
+
+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"],
+}
+
+java_library {
+ name: "Robolectric_shadows_androidx_fragment_upstream",
+ srcs: [
+ "src/main/java/**/*.java",
+ "src/main/java/**/*.kt",
+ ],
+ javacflags: [
+ "-Aorg.robolectric.annotation.processing.shadowPackage=org.robolectric.shadows.androidx.fragment",
+ "-Aorg.robolectric.annotation.processing.sdkCheckMode=ERROR",
+ // Uncomment the below to debug annotation processors not firing.
+ //"-verbose",
+ //"-XprintRounds",
+ //"-XprintProcessorInfo",
+ //"-Xlint",
+ //"-J-verbose",
+ ],
+ libs: [
+ "Robolectric_all-target_upstream",
+ "androidx.fragment_fragment",
+ ],
+ plugins: [
+ "auto_value_plugin_1.9",
+ "auto_value_builder_plugin_1.9",
+ "Robolectric_processor_upstream",
+ ],
+
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/BUILD b/packages/SettingsLib/tests/robotests/fragment/BUILD
new file mode 100644
index 000000000000..393a02e8464c
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/BUILD
@@ -0,0 +1,69 @@
+load("//third_party/java/android/android_sdk_linux/extras/android/compatibility/jetify:jetify.bzl", "jetify_android_library", "jetify_android_local_test")
+
+package(
+ default_applicable_licenses = ["//third_party/java_src/robolectric:license"],
+ default_visibility = ["//third_party/java_src/robolectric:__subpackages__"],
+)
+
+licenses(["notice"])
+
+#==============================================================================
+# Test resources library
+#==============================================================================
+jetify_android_library(
+ name = "test_resources",
+ custom_package = "org.robolectric.shadows.androidx.fragment",
+ manifest = "src/test/AndroidManifest.xml",
+ resource_files = glob(
+ ["src/test/resources/**/*"],
+ ),
+)
+
+#==============================================================================
+# AndroidX fragment module library
+#==============================================================================
+jetify_android_library(
+ name = "androidx_fragment",
+ testonly = 1,
+ srcs = glob(
+ ["src/main/java/**"],
+ ),
+ custom_package = "org.robolectric.shadows.androidx.fragment",
+ javacopts = [
+ "-Aorg.robolectric.annotation.processing.shadowPackage=org.robolectric.shadows.androidx.fragment",
+ ],
+ jetify_sources = True,
+ plugins = [
+ "//java/com/google/thirdparty/robolectric/processor",
+ ],
+ deps = [
+ "//third_party/java/androidx/core",
+ "//third_party/java/androidx/fragment",
+ "//third_party/java/androidx/lifecycle",
+ "//third_party/java_src/robolectric/shadowapi",
+ "//third_party/java_src/robolectric/shadows/framework",
+ ],
+)
+
+[
+ jetify_android_local_test(
+ name = "test_" + src.rstrip(".java"),
+ size = "small",
+ srcs = glob(
+ ["src/test/java/**/*.java"],
+ ),
+ jetify_sources = True,
+ deps = [
+ ":androidx_fragment",
+ ":test_resources",
+ "//third_party/java/androidx/fragment",
+ "//third_party/java/androidx/loader",
+ "//third_party/java/mockito",
+ "//third_party/java/robolectric",
+ "//third_party/java/truth",
+ ],
+ )
+ for src in glob(
+ ["src/test/java/**/*Test.java"],
+ )
+]
diff --git a/packages/SettingsLib/tests/robotests/fragment/build.gradle b/packages/SettingsLib/tests/robotests/fragment/build.gradle
new file mode 100644
index 000000000000..d9dcd84ded89
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/build.gradle
@@ -0,0 +1,48 @@
+plugins {
+ id "net.ltgt.errorprone" version "0.0.13"
+}
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 28
+
+ android {
+ sourceSets {
+ main {
+ res.srcDirs = ['src/test/resources/res']
+ }
+ }
+ testOptions {
+ unitTests {
+ includeAndroidResources = true
+ }
+ }
+ }
+}
+
+dependencies {
+ // Project dependencies
+ compileOnly project(":robolectric")
+
+ // Compile dependencies
+ compileOnly AndroidSdk.MAX_SDK.coordinates
+ compileOnly "androidx.core:core:1.0.0-rc02"
+ compileOnly 'androidx.fragment:fragment:1.0.0-rc02'
+ compileOnly "androidx.lifecycle:lifecycle-viewmodel:2.0.0-rc01"
+ compileOnly "androidx.lifecycle:lifecycle-common:2.0.0-beta01"
+
+ // Testing dependencies
+ testImplementation "com.google.truth:truth:0.44"
+ testImplementation "org.mockito:mockito-core:2.5.4"
+ testImplementation "androidx.arch.core:core-common:2.0.0-beta01"
+ testImplementation "androidx.arch.core:core-runtime:2.0.0-rc01"
+ testImplementation "androidx.collection:collection:1.0.0-rc01"
+ testImplementation "androidx.core:core:1.0.0-rc02"
+ testImplementation 'androidx.fragment:fragment:1.0.0-rc02'
+ testImplementation "androidx.lifecycle:lifecycle-viewmodel:2.0.0-rc01"
+ testImplementation "androidx.lifecycle:lifecycle-common:2.0.0-beta01"
+ testImplementation "androidx.lifecycle:lifecycle-runtime:2.0.0-rc01"
+ testImplementation "androidx.lifecycle:lifecycle-livedata-core:2.0.0-rc01"
+ testImplementation "androidx.loader:loader:1.0.0-rc02"
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java
new file mode 100644
index 000000000000..c688683e7f8a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.robolectric.shadows.androidx.fragment;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.android.controller.ComponentController;
+import org.robolectric.util.ReflectionHelpers;
+
+/** A Controller that can be used to drive the lifecycle of a {@link Fragment} */
+public class FragmentController<F extends Fragment>
+ extends ComponentController<FragmentController<F>, F> {
+
+ private final F mFragment;
+ private final ActivityController<? extends FragmentActivity> mActivityController;
+
+ private FragmentController(F fragment, Class<? extends FragmentActivity> activityClass) {
+ this(fragment, activityClass, null /*intent*/, null /*arguments*/);
+ }
+
+ private FragmentController(
+ F fragment, Class<? extends FragmentActivity> activityClass, Intent intent) {
+ this(fragment, activityClass, intent, null /*arguments*/);
+ }
+
+ private FragmentController(
+ F fragment, Class<? extends FragmentActivity> activityClass, Bundle arguments) {
+ this(fragment, activityClass, null /*intent*/, arguments);
+ }
+
+ private FragmentController(
+ F fragment,
+ Class<? extends FragmentActivity> activityClass,
+ Intent intent,
+ Bundle arguments) {
+ super(fragment, intent);
+ this.mFragment = fragment;
+ if (arguments != null) {
+ this.mFragment.setArguments(arguments);
+ }
+ this.mActivityController =
+ ActivityController.of(ReflectionHelpers.callConstructor(activityClass), intent);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(F fragment) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment and intent.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param intent the intent which will be retained by activity
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(F fragment, Intent intent) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class, intent);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment and arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(F fragment, Bundle arguments) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class, arguments);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment and activity class.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Class<? extends FragmentActivity> activityClass) {
+ return new FragmentController<>(fragment, activityClass);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, intent and arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param intent the intent which will be retained by activity
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Intent intent, Bundle arguments) {
+ return new FragmentController<>(fragment, FragmentControllerActivity.class, intent,
+ arguments);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, activity class and intent.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @param intent the intent which will be retained by activity
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Class<? extends FragmentActivity> activityClass, Intent intent) {
+ return new FragmentController<>(fragment, activityClass, intent);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, activity class and arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment, Class<? extends FragmentActivity> activityClass, Bundle arguments) {
+ return new FragmentController<>(fragment, activityClass, arguments);
+ }
+
+ /**
+ * Generate the {@link FragmentController} for specific fragment, activity class, intent and
+ * arguments.
+ *
+ * @param fragment the fragment which you'd like to drive lifecycle
+ * @param activityClass the activity which will be attached by fragment
+ * @param intent the intent which will be retained by activity
+ * @param arguments the arguments which will be retained by fragment
+ * @return {@link FragmentController}
+ */
+ public static <F extends Fragment> FragmentController<F> of(
+ F fragment,
+ Class<? extends FragmentActivity> activityClass,
+ Intent intent,
+ Bundle arguments) {
+ return new FragmentController<>(fragment, activityClass, intent, arguments);
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity, calling its onCreate() through
+ * onResume() lifecycle methods, and then making it visible. Note that the fragment will be
+ * added
+ * to the view with ID 1.
+ */
+ public static <F extends Fragment> F setupFragment(F fragment) {
+ return FragmentController.of(fragment).create().start().resume().visible().get();
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity, calling its onCreate() through
+ * onResume() lifecycle methods, and then making it visible. Note that the fragment will be
+ * added
+ * to the view with ID 1.
+ */
+ public static <F extends Fragment> F setupFragment(
+ F fragment, Class<? extends FragmentActivity> fragmentActivityClass) {
+ return FragmentController.of(fragment, fragmentActivityClass)
+ .create()
+ .start()
+ .resume()
+ .visible()
+ .get();
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity created with the given bundle,
+ * calling its onCreate() through onResume() lifecycle methods, and then making it visible. Note
+ * that the fragment will be added to the view with ID 1.
+ */
+ public static <F extends Fragment> F setupFragment(
+ F fragment, Class<? extends FragmentActivity> fragmentActivityClass, Bundle bundle) {
+ return FragmentController.of(fragment, fragmentActivityClass)
+ .create(bundle)
+ .start()
+ .resume()
+ .visible()
+ .get();
+ }
+
+ /**
+ * Sets up the given fragment by attaching it to an activity created with the given bundle and
+ * container id, calling its onCreate() through onResume() lifecycle methods, and then making it
+ * visible.
+ */
+ public static <F extends Fragment> F setupFragment(
+ F fragment,
+ Class<? extends FragmentActivity> fragmentActivityClass,
+ int containerViewId,
+ Bundle bundle) {
+ return FragmentController.of(fragment, fragmentActivityClass)
+ .create(containerViewId, bundle)
+ .start()
+ .resume()
+ .visible()
+ .get();
+ }
+
+ /**
+ * Creates the activity with {@link Bundle} and adds the fragment to the view with ID {@code
+ * contentViewId}.
+ */
+ public FragmentController<F> create(final int contentViewId, final Bundle bundle) {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController
+ .create(bundle)
+ .get()
+ .getSupportFragmentManager()
+ .beginTransaction()
+ .add(contentViewId, mFragment)
+ .commit();
+ }
+ });
+ return this;
+ }
+
+ /**
+ * Creates the activity with {@link Bundle} and adds the fragment to it. Note that the fragment
+ * will be added to the view with ID 1.
+ */
+ public FragmentController<F> create(final Bundle bundle) {
+ return create(1, bundle);
+ }
+
+ /**
+ * Creates the {@link Fragment} in a newly initialized state and hence will receive a null
+ * savedInstanceState {@link Bundle parameter}
+ */
+ @Override
+ public FragmentController<F> create() {
+ return create(null);
+ }
+
+ /** Drive lifecycle of activity to Start lifetime */
+ public FragmentController<F> start() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.start();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Resume lifetime */
+ public FragmentController<F> resume() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.resume();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Pause lifetime */
+ public FragmentController<F> pause() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.pause();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Stop lifetime */
+ public FragmentController<F> stop() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.stop();
+ }
+ });
+ return this;
+ }
+
+ /** Drive lifecycle of activity to Destroy lifetime */
+ @Override
+ public FragmentController<F> destroy() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.destroy();
+ }
+ });
+ return this;
+ }
+
+ /** Let activity can be visible lifetime */
+ public FragmentController<F> visible() {
+ shadowMainLooper.runPaused(
+ new Runnable() {
+ @Override
+ public void run() {
+ mActivityController.visible();
+ }
+ });
+ return this;
+ }
+
+ private static class FragmentControllerActivity extends FragmentActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout view = new LinearLayout(this);
+ view.setId(1);
+
+ setContentView(view);
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/MockitoHelper.kt b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
index 5ba54c12b0d0..dd89441255c6 100644
--- a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/MockitoHelper.kt
+++ b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,10 @@
* limitations under the License.
*/
-package com.android.settingslib.spa.testutils
-
-import org.mockito.Mockito
-
/**
- * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when null is
- * returned.
+ * Testing infrastructure for androidx.fragment library.
*
- * Generic T is nullable because implicitly bounded by Any?.
+ * <p>To use this in your project, add the artifact {@code
+ * org.robolectric:shadows-androidx-fragment} to your project.
*/
-fun <T> any(type: Class<T>): T = Mockito.any(type)
-
-inline fun <reified T> any(): T = any(T::class.java)
+package org.robolectric.shadows.androidx.fragment;
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml
new file mode 100644
index 000000000000..8493c0296c8b
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.robolectric.shadows.androidx.fragment">
+
+ <uses-sdk android:targetSdkVersion="28"/>
+</manifest>
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java b/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java
new file mode 100644
index 000000000000..ef6305869b1f
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.robolectric.shadows.androidx.fragment;
+
+import static android.os.Looper.getMainLooper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Tests for {@link FragmentController} */
+@RunWith(RobolectricTestRunner.class)
+public class FragmentControllerTest {
+
+ @After
+ public void tearDown() {
+ TranscriptFragment.clearLifecycleEvents();
+ }
+
+ @Test
+ public void initialNotAttached() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment());
+
+ assertThat(controller.get().getView()).isNull();
+ assertThat(controller.get().getActivity()).isNull();
+ assertThat(controller.get().isAdded()).isFalse();
+ }
+
+ @Test
+ public void initialNotAttached_customActivity() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ assertThat(controller.get().getView()).isNull();
+ assertThat(controller.get().getActivity()).isNull();
+ assertThat(controller.get().isAdded()).isFalse();
+ }
+
+ @Test
+ public void attachedAfterCreate() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment());
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ }
+
+ @Test
+ public void attachedAfterCreate_customActivity() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().getActivity()).isInstanceOf(TestActivity.class);
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ }
+
+ @Test
+ public void attachedAfterCreate_customizedViewId() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), CustomizedViewIdTestActivity.class);
+
+ controller.create(R.id.custom_activity_view, null).start();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ assertThat((TextView) controller.get().getView().findViewById(R.id.tacos)).isNotNull();
+ }
+
+ @Test
+ public void hasViewAfterStart() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment());
+
+ controller.create().start();
+
+ assertThat(controller.get().getView()).isNotNull();
+ }
+
+ @Test
+ public void isResumed() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isTrue();
+ assertThat((TextView) controller.get().getView().findViewById(R.id.tacos)).isNotNull();
+ }
+
+ @Test
+ public void isPaused() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume().pause();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ assertThat(controller.get().getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume", "onPause")
+ .inOrder();
+ }
+
+ @Test
+ public void isStopped() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume().pause().stop();
+
+ assertThat(controller.get().getView()).isNotNull();
+ assertThat(controller.get().getActivity()).isNotNull();
+ assertThat(controller.get().isAdded()).isTrue();
+ assertThat(controller.get().isResumed()).isFalse();
+ assertThat(controller.get().getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume", "onPause", "onStop")
+ .inOrder();
+ }
+
+ @Test
+ public void withIntent() {
+ final Intent intent = generateTestIntent();
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class, intent);
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+ final Intent intentInFragment = controller.get().getActivity().getIntent();
+
+ assertThat(intentInFragment.getAction()).isEqualTo("test_action");
+ assertThat(intentInFragment.getExtras().getString("test_key")).isEqualTo("test_value");
+ }
+
+ @Test
+ public void withArguments() {
+ final Bundle bundle = generateTestBundle();
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class, bundle);
+
+ controller.create();
+ final Bundle args = controller.get().getArguments();
+
+ assertThat(args.getString("test_key")).isEqualTo("test_value");
+ }
+
+ @Test
+ public void withIntentAndArguments() {
+ final Bundle bundle = generateTestBundle();
+ final Intent intent = generateTestIntent();
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class, intent, bundle);
+
+ controller.create();
+ shadowOf(getMainLooper()).idle();
+ final Intent intentInFragment = controller.get().getActivity().getIntent();
+ final Bundle args = controller.get().getArguments();
+
+ assertThat(intentInFragment.getAction()).isEqualTo("test_action");
+ assertThat(intentInFragment.getExtras().getString("test_key")).isEqualTo("test_value");
+ assertThat(args.getString("test_key")).isEqualTo("test_value");
+ }
+
+ @Test
+ public void visible() {
+ final FragmentController<TranscriptFragment> controller =
+ FragmentController.of(new TranscriptFragment(), TestActivity.class);
+
+ controller.create().start().resume();
+
+ assertThat(controller.get().isVisible()).isFalse();
+
+ controller.visible();
+
+ assertThat(controller.get().isVisible()).isTrue();
+ }
+
+ @Test
+ public void setupFragmentWithFragment_fragmentHasCorrectLifecycle() {
+ TranscriptFragment fragment = FragmentController.setupFragment(new TranscriptFragment());
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ @Test
+ public void setupFragmentWithFragmentAndActivity_fragmentHasCorrectLifecycle() {
+ TranscriptFragment fragment =
+ FragmentController.setupFragment(new TranscriptFragment(), TestActivity.class);
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ @Test
+ public void setupFragmentWithFragmentAndActivityAndBundle_HasCorrectLifecycle() {
+ Bundle testBundle = generateTestBundle();
+ TranscriptFragment fragment =
+ FragmentController.setupFragment(new TranscriptFragment(), TestActivity.class,
+ testBundle);
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ @Test
+ public void
+ setupFragmentWithFragment_Activity_ContainViewIdAndBundle_HasCorrectLifecycle() {
+ Bundle testBundle = generateTestBundle();
+ TranscriptFragment fragment =
+ FragmentController.setupFragment(
+ new TranscriptFragment(),
+ CustomizedViewIdTestActivity.class,
+ R.id.custom_activity_view,
+ testBundle);
+
+ assertThat(fragment.getLifecycleEvents())
+ .containsExactly("onCreate", "onStart", "onResume")
+ .inOrder();
+ assertThat(fragment.isVisible()).isTrue();
+ }
+
+ private Intent generateTestIntent() {
+ final Intent testIntent = new Intent("test_action").putExtra("test_key", "test_value");
+ return testIntent;
+ }
+
+ private Bundle generateTestBundle() {
+ final Bundle testBundle = new Bundle();
+ testBundle.putString("test_key", "test_value");
+
+ return testBundle;
+ }
+
+ /** A Fragment which can record lifecycle status for test. */
+ public static class TranscriptFragment extends Fragment {
+
+ public static final List<String> sLifecycleEvents = new ArrayList<>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ sLifecycleEvents.add("onCreate");
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ sLifecycleEvents.add("onStart");
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ sLifecycleEvents.add("onResume");
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ sLifecycleEvents.add("onPause");
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ sLifecycleEvents.add("onStop");
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_contents, container, false);
+ }
+
+ public List<String> getLifecycleEvents() {
+ return sLifecycleEvents;
+ }
+
+ public static void clearLifecycleEvents() {
+ sLifecycleEvents.clear();
+ }
+ }
+
+ /** A Activity which set a default view for test. */
+ public static class TestActivity extends FragmentActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout view = new LinearLayout(this);
+ view.setId(1);
+
+ setContentView(view);
+ }
+ }
+
+ /** A Activity which has a custom view for test. */
+ public static class CustomizedViewIdTestActivity extends FragmentActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.custom_activity_view);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml
new file mode 100644
index 000000000000..c074f30964db
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/custom_activity_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+</LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml
new file mode 100644
index 000000000000..425b2bb6a0d9
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tacos"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TACOS"/>
+
+ <TextView
+ android:id="@+id/burritos"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="BURRITOS"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 4a913c87bddf..bb72375499c1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -58,12 +57,10 @@ import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowSettings;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {UtilsTest.ShadowSecure.class, UtilsTest.ShadowLocationManager.class})
+@Config(shadows = {UtilsTest.ShadowLocationManager.class})
public class UtilsTest {
private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100};
private static final String TAG = "UtilsTest";
@@ -94,7 +91,7 @@ public class UtilsTest {
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager);
when(mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
- ShadowSecure.reset();
+ ShadowSettings.ShadowSecure.reset();
mAudioManager = mContext.getSystemService(AudioManager.class);
}
@@ -111,15 +108,16 @@ public class UtilsTest {
Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
- .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
+ Settings.Secure.LOCATION_CHANGER,
+ Settings.Secure.LOCATION_CHANGER_UNKNOWN)).isEqualTo(
+ Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
}
@Test
public void testFormatPercentage_RoundTrue_RoundUpIfPossible() {
- final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1,
- PERCENTAGE_1, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50,
- PERCENTAGE_100};
+ final String[] expectedPercentages =
+ {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1, PERCENTAGE_1, PERCENTAGE_49,
+ PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50, PERCENTAGE_100};
for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) {
final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], true);
@@ -129,9 +127,9 @@ public class UtilsTest {
@Test
public void testFormatPercentage_RoundFalse_NoRound() {
- final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0,
- PERCENTAGE_0, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50,
- PERCENTAGE_100};
+ final String[] expectedPercentages =
+ {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_49,
+ PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_100};
for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) {
final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], false);
@@ -143,12 +141,7 @@ public class UtilsTest {
public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() {
Resources resources = mock(Resources.class);
when(resources.getInteger(
- eq(
- com.android
- .internal
- .R
- .integer
- .config_storageManagerDaystoRetainDefault)))
+ eq(com.android.internal.R.integer.config_storageManagerDaystoRetainDefault)))
.thenReturn(60);
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
@@ -163,31 +156,6 @@ public class UtilsTest {
return intent -> TextUtils.equals(expected, intent.getAction());
}
- @Implements(value = Settings.Secure.class)
- public static class ShadowSecure extends ShadowSettings.ShadowSecure {
- private static Map<String, Integer> map = new HashMap<>();
-
- @Implementation
- public static boolean putIntForUser(ContentResolver cr, String name, int value,
- int userHandle) {
- map.put(name, value);
- return true;
- }
-
- @Implementation
- public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
- if (map.containsKey(name)) {
- return map.get(name);
- } else {
- return def;
- }
- }
-
- public static void reset() {
- map.clear();
- }
- }
-
@Implements(value = LocationManager.class)
public static class ShadowLocationManager {
@@ -337,9 +305,8 @@ public class UtilsTest {
@Test
public void getBatteryStatus_statusIsFull_returnFullString() {
- final Intent intent = new Intent()
- .putExtra(BatteryManager.EXTRA_LEVEL, 100)
- .putExtra(BatteryManager.EXTRA_SCALE, 100);
+ final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra(
+ BatteryManager.EXTRA_SCALE, 100);
final Resources resources = mContext.getResources();
assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo(
@@ -348,9 +315,8 @@ public class UtilsTest {
@Test
public void getBatteryStatus_statusIsFullAndUseCompactStatus_returnFullyChargedString() {
- final Intent intent = new Intent()
- .putExtra(BatteryManager.EXTRA_LEVEL, 100)
- .putExtra(BatteryManager.EXTRA_SCALE, 100);
+ final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra(
+ BatteryManager.EXTRA_SCALE, 100);
final Resources resources = mContext.getResources();
assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo(
@@ -516,7 +482,6 @@ public class UtilsTest {
when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
when(mUsbPortStatus.isConnected()).thenReturn(true);
- when(mUsbPortStatus.getComplianceWarnings())
- .thenReturn(new int[]{complianceWarningType});
+ when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[]{complianceWarningType});
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
index 44fdaec49f73..3de84464af2e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
@@ -23,13 +23,17 @@ import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
+import com.android.settingslib.testutils.shadow.ShadowSecure;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowSecure.class})
public class AccessibilityUtilsTest {
private Context mContext;
@@ -46,7 +50,7 @@ public class AccessibilityUtilsTest {
@Test
public void getEnabledServicesFromSettings_badFormat_emptyResult() {
- Settings.Secure.putStringForUser(
+ ShadowSecure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
":",
UserHandle.myUserId());
@@ -57,7 +61,7 @@ public class AccessibilityUtilsTest {
@Test
public void getEnabledServicesFromSettings_1Service_1result() {
final ComponentName cn = new ComponentName("pkg", "serv");
- Settings.Secure.putStringForUser(
+ ShadowSecure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
cn.flattenToString() + ":",
UserHandle.myUserId());
@@ -70,7 +74,7 @@ public class AccessibilityUtilsTest {
public void getEnabledServicesFromSettings_2Services_2results() {
final ComponentName cn1 = new ComponentName("pkg", "serv");
final ComponentName cn2 = new ComponentName("pkg", "serv2");
- Settings.Secure.putStringForUser(
+ ShadowSecure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
cn1.flattenToString() + ":" + cn2.flattenToString(),
UserHandle.myUserId());
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
index cb62a735434d..f9505ddb7e2f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
@@ -37,6 +37,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.LongSparseArray;
+import com.android.settingslib.testutils.shadow.ShadowPermissionChecker;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +47,6 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowPermissionChecker;
import java.time.Clock;
import java.util.ArrayList;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index dd8d54a62ff4..a2e8c5956100 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -38,6 +38,7 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
@@ -167,6 +168,7 @@ public class MetricsFeatureProviderTest {
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void getAttribution_notSet_shouldReturnUnknown() {
final Activity activity = Robolectric.setupActivity(Activity.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
index d67d44b9035d..25833b3ddbba 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
@@ -36,6 +36,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.CujType;
+import com.android.settingslib.testutils.OverpoweredReflectionHelper;
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
import org.junit.Before;
@@ -51,7 +52,6 @@ import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
-import org.robolectric.util.ReflectionHelpers;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -83,8 +83,10 @@ public class SettingsJankMonitorTest {
public void setUp() {
ShadowInteractionJankMonitor.reset();
when(ShadowInteractionJankMonitor.MOCK_INSTANCE.begin(any())).thenReturn(true);
- ReflectionHelpers.setStaticField(SettingsJankMonitor.class, "scheduledExecutorService",
- mScheduledExecutorService);
+ OverpoweredReflectionHelper
+ .setStaticField(SettingsJankMonitor.class,
+ "scheduledExecutorService",
+ mScheduledExecutorService);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
index cf702b531a3c..471dac05e6b4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
@@ -37,8 +37,10 @@ import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.LooperMode;
@RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.PAUSED)
public class HideNonSystemOverlayMixinTest {
private ActivityController<TestActivity> mActivityController;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
index 3475ff7d96f8..b009abd87b1c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
@@ -22,13 +22,14 @@ import android.content.Context;
import android.os.UserManager;
import android.provider.Settings;
+import com.android.settingslib.testutils.shadow.ShadowUserManager;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowUserManager;
@RunWith(RobolectricTestRunner.class)
public class DevelopmentSettingsEnablerTest {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
index 8e33ca338eb1..0cabab241be4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
@@ -269,6 +270,7 @@ public class LicenseHtmlGeneratorFromXmlTest {
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void testGenerateHtmlWithCustomHeading() throws Exception {
List<File> xmlFiles = new ArrayList<>();
Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>();
@@ -292,6 +294,7 @@ public class LicenseHtmlGeneratorFromXmlTest {
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void testGenerateNewHtmlWithCustomHeading() throws Exception {
List<File> xmlFiles = new ArrayList<>();
Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java
new file mode 100644
index 000000000000..9e9725fc3710
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@LooperMode(LooperMode.Mode.LEGACY)
+package com.android.settingslib;
+
+import org.robolectric.annotation.LooperMode;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
index d41d5112e6b2..faec02f7a0d4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
@@ -27,6 +27,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
@RunWith(RobolectricTestRunner.class)
public class AnimatedImageViewTest {
@@ -40,6 +41,7 @@ public class AnimatedImageViewTest {
}
@Test
+ @LooperMode(LooperMode.Mode.PAUSED)
public void testAnimation_ViewVisible_AnimationRunning() {
mAnimatedImageView.setVisibility(View.VISIBLE);
mAnimatedImageView.setAnimating(true);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
index 0a48f19a3021..0d889139e8b4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
@@ -41,6 +41,8 @@ import androidx.annotation.ColorRes;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.R;
+import com.android.settingslib.testutils.OverpoweredReflectionHelper;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -502,14 +504,18 @@ public class BannerMessagePreferenceTest {
private void assumeAndroidR() {
ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", 30);
ReflectionHelpers.setStaticField(Build.VERSION.class, "CODENAME", "R");
- ReflectionHelpers.setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", false);
+ OverpoweredReflectionHelper
+ .setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", false);
// Reset view holder to use correct layout.
}
+
+
private void assumeAndroidS() {
ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", 31);
ReflectionHelpers.setStaticField(Build.VERSION.class, "CODENAME", "S");
- ReflectionHelpers.setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", true);
+ OverpoweredReflectionHelper
+ .setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", true);
// Re-inflate view to update layout.
setUpViewHolder();
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java
new file mode 100644
index 000000000000..4fcc5a1f7000
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.testutils;
+
+import org.robolectric.util.ReflectionHelpers;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class OverpoweredReflectionHelper extends ReflectionHelpers {
+
+ /**
+ * Robolectric upstream does not rely on or encourage this behaviour.
+ *
+ * @param field
+ */
+ private static void makeFieldVeryAccessible(Field field) {
+ field.setAccessible(true);
+ // remove 'final' modifier if present
+ if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
+ Field modifiersField = getModifiersField();
+ modifiersField.setAccessible(true);
+ try {
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ } catch (IllegalAccessException e) {
+
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ private static Field getModifiersField() {
+ try {
+ return Field.class.getDeclaredField("modifiers");
+ } catch (NoSuchFieldException e) {
+ try {
+ Method getFieldsMethod =
+ Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
+ getFieldsMethod.setAccessible(true);
+ Field[] fields = (Field[]) getFieldsMethod.invoke(Field.class, false);
+ for (Field modifiersField : fields) {
+ if ("modifiers".equals(modifiersField.getName())) {
+ return modifiersField;
+ }
+ }
+ } catch (ReflectiveOperationException innerE) {
+ throw new AssertionError(innerE);
+ }
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Reflectively set the value of a static field.
+ *
+ * @param field Field object.
+ * @param fieldNewValue The new value.
+ */
+ public static void setStaticField(Field field, Object fieldNewValue) {
+ try {
+ makeFieldVeryAccessible(field);
+ field.setAccessible(true);
+ field.set(null, fieldNewValue);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Reflectively set the value of a static field.
+ *
+ * @param clazz Target class.
+ * @param fieldName The field name.
+ * @param fieldNewValue The new value.
+ */
+ public static void setStaticField(Class<?> clazz, String fieldName, Object fieldNewValue) {
+ try {
+ setStaticField(clazz.getDeclaredField(fieldName), fieldNewValue);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
index 924eb047c340..0b9ba8d044ce 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
@@ -16,23 +16,27 @@
package com.android.settingslib.testutils.shadow;
+import static android.os.Build.VERSION_CODES.O;
+
import android.app.ActivityManager;
+import android.app.IActivityManager;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.shadow.api.Shadow;
+import org.robolectric.util.ReflectionHelpers;
@Implements(ActivityManager.class)
public class ShadowActivityManager {
private static int sCurrentUserId = 0;
- private int mUserSwitchedTo = -1;
+ private static int sUserSwitchedTo = -1;
@Resetter
- public void reset() {
+ public static void reset() {
sCurrentUserId = 0;
- mUserSwitchedTo = 0;
+ sUserSwitchedTo = 0;
}
@Implementation
@@ -42,16 +46,21 @@ public class ShadowActivityManager {
@Implementation
protected boolean switchUser(int userId) {
- mUserSwitchedTo = userId;
+ sUserSwitchedTo = userId;
return true;
}
+ @Implementation(minSdk = O)
+ protected static IActivityManager getService() {
+ return ReflectionHelpers.createNullProxy(IActivityManager.class);
+ }
+
public boolean getSwitchUserCalled() {
- return mUserSwitchedTo != -1;
+ return sUserSwitchedTo != -1;
}
public int getUserSwitchedTo() {
- return mUserSwitchedTo;
+ return sUserSwitchedTo;
}
public static void setCurrentUser(int userId) {
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
index 2c0792fd57bd..bbfdb7f91c4b 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
@@ -29,7 +29,7 @@ public class ShadowDefaultDialerManager {
private static String sDefaultDialer;
@Resetter
- public void reset() {
+ public static void reset() {
sDefaultDialer = null;
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java
new file mode 100644
index 000000000000..fae3aeafd5fb
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.testutils.shadow;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.PermissionChecker;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.HashMap;
+import java.util.Map;
+/** Shadow class of {@link PermissionChecker}. */
+@Implements(PermissionChecker.class)
+public class ShadowPermissionChecker {
+ private static final Map<String, Map<String, Integer>> RESULTS = new HashMap<>();
+ /** Set the result of permission check for a specific permission. */
+ public static void setResult(String packageName, String permission, int result) {
+ if (!RESULTS.containsKey(packageName)) {
+ RESULTS.put(packageName, new HashMap<>());
+ }
+ RESULTS.get(packageName).put(permission, result);
+ }
+ /** Check the permission of calling package. */
+ @Implementation
+ public static int checkCallingPermissionForDataDelivery(
+ Context context,
+ String permission,
+ String packageName,
+ String attributionTag,
+ String message) {
+ return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
+ ? RESULTS.get(packageName).get(permission)
+ : PermissionChecker.checkCallingPermissionForDataDelivery(
+ context, permission, packageName, attributionTag, message);
+ }
+ /** Check general permission. */
+ @Implementation
+ public static int checkPermissionForDataDelivery(
+ Context context,
+ String permission,
+ int pid,
+ int uid,
+ String packageName,
+ String attributionTag,
+ String message) {
+ return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
+ ? RESULTS.get(packageName).get(permission)
+ : PermissionChecker.checkPermissionForDataDelivery(
+ context, permission, pid, uid, packageName, attributionTag, message);
+ }
+ /** Check general permission. */
+ @Implementation
+ public static int checkPermissionForPreflight(@NonNull Context context,
+ @NonNull String permission, int pid, int uid, @Nullable String packageName) {
+ return checkPermissionForPreflight(context, permission, new AttributionSource(
+ uid, packageName, null /*attributionTag*/));
+ }
+ /** Check general permission. */
+ @Implementation
+ public static int checkPermissionForPreflight(@NonNull Context context,
+ @NonNull String permission, @NonNull AttributionSource attributionSource) {
+ final String packageName = attributionSource.getPackageName();
+ return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
+ ? RESULTS.get(packageName).get(permission)
+ : PermissionChecker.checkPermissionForPreflight(
+ context, permission, attributionSource);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java
new file mode 100644
index 000000000000..70ebc6791538
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.testutils.shadow;
+
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowSettings;
+
+@Implements(value = Settings.Secure.class)
+public class ShadowSecure extends ShadowSettings.ShadowSecure {
+ @Implementation(minSdk = JELLY_BEAN_MR1)
+ public static boolean putStringForUser(ContentResolver cr, String name, String value,
+ int userHandle) {
+ return putString(cr, name, value);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
index 381d072b6fe1..5ac0a87c1ae9 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
@@ -31,7 +31,7 @@ public class ShadowSmsApplication {
private static ComponentName sDefaultSmsApplication;
@Resetter
- public void reset() {
+ public static void reset() {
sDefaultSmsApplication = null;
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index ca1eefcad7de..60d7721242b8 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -16,20 +16,28 @@
package com.android.settingslib.testutils.shadow;
+import static android.os.Build.VERSION_CODES.N_MR1;
+
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
+import android.os.UserHandle;
import android.os.UserManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowBuild;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@Implements(value = UserManager.class)
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
private List<UserInfo> mUserInfos = addProfile(0, "Owner");
+ private final Map<Integer, UserProperties> mUserPropertiesMap = new HashMap<>();
@Implementation
protected static UserManager get(Context context) {
@@ -62,4 +70,37 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
protected List<UserInfo> getProfiles(@UserIdInt int userHandle) {
return getProfiles();
}
+
+ /**
+ * @return {@code false} by default, or the value specified via {@link #setIsAdminUser(boolean)}
+ */
+ @Implementation(minSdk = N_MR1)
+ public boolean isAdminUser() {
+ return getUserInfo(UserHandle.myUserId()).isAdmin();
+ }
+
+ /**
+ * Sets that the current user is an admin user; controls the return value of
+ * {@link UserManager#isAdminUser}.
+ */
+ public void setIsAdminUser(boolean isAdminUser) {
+ UserInfo userInfo = getUserInfo(UserHandle.myUserId());
+ if (isAdminUser) {
+ userInfo.flags |= UserInfo.FLAG_ADMIN;
+ } else {
+ userInfo.flags &= ~UserInfo.FLAG_ADMIN;
+ }
+ }
+
+ public void setupUserProperty(int userId, int showInSettings) {
+ UserProperties userProperties = new UserProperties(new UserProperties.Builder()
+ .setShowInSettings(showInSettings).build());
+ mUserPropertiesMap.putIfAbsent(userId, userProperties);
+ }
+
+ @Implementation(minSdk = ShadowBuild.UPSIDE_DOWN_CAKE)
+ protected UserProperties getUserProperties(UserHandle user) {
+ return mUserPropertiesMap.getOrDefault(user.getIdentifier(),
+ new UserProperties(new UserProperties.Builder().build()));
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index d1f7f2fe3516..fa2d677e85c2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -24,7 +24,7 @@ public class GlobalSettings {
/**
* These keys may be mentioned in the SETTINGS_TO_BACKUP arrays in SystemSettings
* and SecureSettings as well. This is because those tables drive both backup and
- * restore, and restore needs to properly whitelist keys that used to live
+ * restore, and restore needs to properly allowlist keys that used to live
* in those namespaces.
*
* NOTE: Settings are backed up and restored in the order they appear
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index c830d6b2b611..7b49608ceb7e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -927,7 +927,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
@VisibleForTesting
SettingsBackupWhitelist getBackupWhitelist(Uri contentUri) {
// Figure out the white list and redirects to the global table. We restore anything
- // in either the backup whitelist or the legacy-restore whitelist for this table.
+ // in either the backup allowlist or the legacy-restore allowlist for this table.
String[] whitelist;
Map<String, Validator> validators = null;
if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
@@ -1474,7 +1474,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
/**
- * Store the whitelist of settings to be backed up and validators for them.
+ * Store the allowlist of settings to be backed up and validators for them.
*/
@VisibleForTesting
static class SettingsBackupWhitelist {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7e9795643849..5f4f3175ac69 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -251,7 +251,7 @@ public class SettingsProvider extends ContentProvider {
public static final int WRITE_FALLBACK_SETTINGS_FILES_JOB_ID = 1;
public static final long ONE_DAY_INTERVAL_MILLIS = 24 * 60 * 60 * 1000L;
- // Overlay specified settings whitelisted for Instant Apps
+ // Overlay specified settings allowlisted for Instant Apps
private static final Set<String> OVERLAY_ALLOWED_GLOBAL_INSTANT_APP_SETTINGS = new ArraySet<>();
private static final Set<String> OVERLAY_ALLOWED_SYSTEM_INSTANT_APP_SETTINGS = new ArraySet<>();
private static final Set<String> OVERLAY_ALLOWED_SECURE_INSTANT_APP_SETTINGS = new ArraySet<>();
@@ -1157,8 +1157,6 @@ public class SettingsProvider extends ContentProvider {
Slog.v(LOG_TAG, "getConfigSetting(" + name + ")");
}
- Settings.Config.enforceReadPermission(/*namespace=*/name.split("/")[0]);
-
// Get the value.
synchronized (mLock) {
return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_CONFIG,
@@ -1338,9 +1336,6 @@ public class SettingsProvider extends ContentProvider {
Slog.v(LOG_TAG, "getAllConfigFlags() for " + prefix);
}
- Settings.Config.enforceReadPermission(
- prefix != null ? prefix.split("/")[0] : null);
-
synchronized (mLock) {
// Get the settings.
SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
@@ -2155,7 +2150,7 @@ public class SettingsProvider extends ContentProvider {
@GuardedBy("mLock")
private List<String> getSettingsNamesLocked(int settingsType, int userId) {
- // Don't enforce the instant app whitelist for now -- its too prone to unintended breakage
+ // Don't enforce the instant app allowlist for now -- its too prone to unintended breakage
// in the current form.
return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
}
@@ -2196,7 +2191,7 @@ public class SettingsProvider extends ContentProvider {
}
if (!getInstantAppAccessibleSettings(settingsType).contains(settingName)
&& !getOverlayInstantAppAccessibleSettings(settingsType).contains(settingName)) {
- // Don't enforce the instant app whitelist for now -- its too prone to unintended
+ // Don't enforce the instant app allowlist for now -- its too prone to unintended
// breakage in the current form.
Slog.w(LOG_TAG, "Instant App " + ai.packageName
+ " trying to access unexposed setting, this will be an error in the future.");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 73ead3c4d61f..0a98032e26d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -845,6 +845,7 @@ final class SettingsState {
private void doWriteState() {
boolean wroteState = false;
+ String settingFailedToBePersisted = null;
final int version;
final ArrayMap<String, Setting> settings;
final ArrayMap<String, String> namespaceBannedHashes;
@@ -895,8 +896,14 @@ final class SettingsState {
}
}
} catch (IOException ex) {
- Slog.e(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName()
+ Slog.e(LOG_TAG, "[ABORT PERSISTING]" + setting.getName()
+ " due to error writing to disk", ex);
+ // A setting failed to be written. Abort the serialization to avoid leaving
+ // a partially serialized setting on disk, which can cause parsing errors.
+ // Note down the problematic setting, so that we can delete it before trying
+ // again to persist the rest of the settings.
+ settingFailedToBePersisted = setting.getName();
+ throw ex;
}
}
serializer.endTag(null, TAG_SETTINGS);
@@ -922,14 +929,14 @@ final class SettingsState {
Slog.i(LOG_TAG, "[PERSIST END]");
}
} catch (Throwable t) {
- Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t);
+ Slog.wtf(LOG_TAG, "Failed to write settings, restoring old file", t);
if (t instanceof IOException) {
- if (DEBUG) {
- // we failed to create a directory, so log the permissions and existence
- // state for the settings file and directory
- logSettingsDirectoryInformation(destination.getBaseFile());
- }
if (t.getMessage().contains("Couldn't create directory")) {
+ if (DEBUG) {
+ // we failed to create a directory, so log the permissions and existence
+ // state for the settings file and directory
+ logSettingsDirectoryInformation(destination.getBaseFile());
+ }
// attempt to create the directory with Files.createDirectories, which
// throws more informative errors than File.mkdirs.
Path parentPath = destination.getBaseFile().getParentFile().toPath();
@@ -950,7 +957,15 @@ final class SettingsState {
}
}
- if (wroteState) {
+ if (!wroteState) {
+ if (settingFailedToBePersisted != null) {
+ synchronized (mLock) {
+ // Delete the problematic setting. This will schedule a write as well.
+ deleteSettingLocked(settingFailedToBePersisted);
+ }
+ }
+ } else {
+ // success
synchronized (mLock) {
addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null);
}
@@ -1110,7 +1125,10 @@ final class SettingsState {
} catch (FileNotFoundException fnfe) {
final String message = "No fallback file found for: " + mStatePersistFile;
Slog.wtf(LOG_TAG, message);
- throw new IllegalStateException(message);
+ if (!isConfigSettingsKey(mKey)) {
+ // Allow partially deserialized config settings because they can be updated later
+ throw new IllegalStateException(message);
+ }
}
if (parseStateFromXmlStreamLocked(in)) {
// Parsed state from fallback file. Restore original file with fallback file
@@ -1122,7 +1140,10 @@ final class SettingsState {
} else {
final String message = "Failed parsing settings file: " + mStatePersistFile;
Slog.wtf(LOG_TAG, message);
- throw new IllegalStateException(message);
+ if (!isConfigSettingsKey(mKey)) {
+ // Allow partially deserialized config settings because they can be updated later
+ throw new IllegalStateException(message);
+ }
}
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml
index 81b3152375ff..1f5765465075 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml
@@ -16,6 +16,10 @@
-->
<resources>
+ <style name="AccessibilityMenuSettings" parent="android:Theme.DeviceDefault.DayNight">
+ <item name="android:windowLightStatusBar">false</item>
+ </style>
+
<!--Adds the theme to support SnackBar component and user configurable theme. -->
<style name="ServiceTheme" parent="android:Theme.DeviceDefault.DayNight">
<item name="android:colorControlNormal">@color/colorControlNormal</item>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
index 2009cd1df4e5..a2508cdf4f16 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
@@ -17,7 +17,9 @@
<resources>
<!--The theme is for preference CollapsingToolbarBaseActivity settings-->
- <style name="AccessibilityMenuSettings" parent="android:Theme.DeviceDefault.DayNight" />
+ <style name="AccessibilityMenuSettings" parent="android:Theme.DeviceDefault.DayNight">
+ <item name="android:windowLightStatusBar">true</item>
+ </style>
<!--Adds the theme to support SnackBar component and user configurable theme. -->
<style name="ServiceTheme" parent="android:Theme.DeviceDefault.Light">
diff --git a/packages/SystemUI/docs/qs-tiles.md b/packages/SystemUI/docs/qs-tiles.md
index 488f8c728d82..bd0b4abbeb34 100644
--- a/packages/SystemUI/docs/qs-tiles.md
+++ b/packages/SystemUI/docs/qs-tiles.md
@@ -123,7 +123,7 @@ A third party tile is any Quick Settings tile that is provided by an app (that's
### API classes
-The classes that define the public API are in [core/java/android/service/quicksettings](core/java/android/service/quicksettings).
+The classes that define the public API are in [core/java/android/service/quicksettings](/core/java/android/service/quicksettings).
#### Tile
diff --git a/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
new file mode 100644
index 000000000000..952f056b3023
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/carrier_combo"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="horizontal" >
+
+ <com.android.systemui.util.AutoMarqueeTextView
+ android:id="@+id/mobile_carrier_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginEnd="@dimen/qs_carrier_margin_width"
+ android:visibility="gone"
+ android:textDirection="locale"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:singleLine="true"
+ android:maxEms="7"/>
+
+ <include layout="@layout/status_bar_mobile_signal_group_new" />
+
+</com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView>
+
diff --git a/packages/SystemUI/res/drawable/auth_credential_emergency_button_background.xml b/packages/SystemUI/res/drawable/auth_credential_emergency_button_background.xml
new file mode 100644
index 000000000000..85450b446d48
--- /dev/null
+++ b/packages/SystemUI/res/drawable/auth_credential_emergency_button_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape android:shape="rectangle">
+ <corners android:radius="25dp"/>
+ <solid android:color="@android:color/system_accent3_100" />
+ </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
index 4a9d41fae1d5..b83f15a1a247 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -14,6 +14,4 @@ Copyright (C) 2015 The Android Open Source Project
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="3dp"
- android:insetRight="3dp"
android:drawable="@drawable/ic_speaker_mute" />
diff --git a/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml b/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml
new file mode 100644
index 000000000000..24222f7642be
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml
@@ -0,0 +1,101 @@
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <RelativeLayout
+ android:id="@+id/auth_credential_header"
+ style="?headerStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+
+ <ImageView
+ android:id="@+id/icon"
+ style="?headerIconStyle"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:contentDescription="@null"/>
+
+ <TextView
+ android:id="@+id/title"
+ style="?titleTextAppearance"
+ android:layout_below="@id/icon"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/subtitle"
+ style="?subTitleTextAppearance"
+ android:layout_below="@id/title"
+ android:layout_alignParentLeft="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/description"
+ style="?descriptionTextAppearance"
+ android:layout_below="@id/subtitle"
+ android:layout_alignParentLeft="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/auth_credential_input"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="vertical">
+
+ <ImeAwareEditText
+ android:id="@+id/lockPassword"
+ style="?passwordTextAppearance"
+ android:layout_width="208dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
+ android:inputType="textPassword"
+ android:minHeight="48dp"/>
+
+ <TextView
+ android:id="@+id/error"
+ style="?errorTextAppearance"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/emergencyCallButton"
+ style="@style/AuthCredentialEmergencyButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
+ android:text="@string/work_challenge_emergency_button_text"/>
+ </FrameLayout>
+
+</merge>
diff --git a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml
index e2ce34f5008e..8ac7583088f9 100644
--- a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml
@@ -23,67 +23,6 @@
android:elevation="@dimen/biometric_dialog_elevation"
android:theme="?app:attr/lockPinPasswordStyle">
- <RelativeLayout
- android:id="@+id/auth_credential_header"
- style="?headerStyle"
- android:layout_width="wrap_content"
- android:layout_height="match_parent">
-
- <ImageView
- android:id="@+id/icon"
- style="?headerIconStyle"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:contentDescription="@null"/>
-
- <TextView
- android:id="@+id/title"
- style="?titleTextAppearance"
- android:layout_below="@id/icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- android:id="@+id/subtitle"
- style="?subTitleTextAppearance"
- android:layout_below="@id/title"
- android:layout_alignParentLeft="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- android:id="@+id/description"
- style="?descriptionTextAppearance"
- android:layout_below="@id/subtitle"
- android:layout_alignParentLeft="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </RelativeLayout>
-
- <LinearLayout
- android:id="@+id/auth_credential_input"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <ImeAwareEditText
- android:id="@+id/lockPassword"
- style="?passwordTextAppearance"
- android:layout_width="208dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
- android:inputType="textPassword"
- android:minHeight="48dp" />
-
- <TextView
- android:id="@+id/error"
- style="?errorTextAppearance"
- android:layout_gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
+ <include layout="@layout/auth_credential_password_pin_content_view" />
</com.android.systemui.biometrics.ui.CredentialPasswordView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
index 88f138f9b093..d5af37733b3b 100644
--- a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
@@ -60,27 +60,44 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/error"
+ style="?errorTextAppearanceLand"
+ android:layout_below="@id/description"
+ android:layout_alignParentLeft="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
</RelativeLayout>
- <FrameLayout
+ <RelativeLayout
android:layout_weight="1"
- style="?containerStyle"
android:layout_width="0dp"
android:layout_height="match_parent">
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPattern"
- android:layout_gravity="center"
- android:layout_width="@dimen/biometric_auth_pattern_view_size"
- android:layout_height="@dimen/biometric_auth_pattern_view_size"/>
-
- <TextView
- android:id="@+id/error"
- style="?errorTextAppearance"
+ <FrameLayout
+ style="?containerStyle"
+ android:layout_above="@id/emergencyCallButton"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom"/>
+ android:layout_height="match_parent">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_gravity="center"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"/>
+ </FrameLayout>
- </FrameLayout>
+ <Button
+ android:id="@+id/emergencyCallButton"
+ style="@style/AuthCredentialEmergencyButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="35dp"
+ android:visibility="gone"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:text="@string/work_challenge_emergency_button_text"/>
+ </RelativeLayout>
</com.android.systemui.biometrics.ui.CredentialPatternView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/auth_credential_pin_view.xml b/packages/SystemUI/res/layout-land/auth_credential_pin_view.xml
new file mode 100644
index 000000000000..8ac7583088f9
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/auth_credential_pin_view.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<com.android.systemui.biometrics.ui.CredentialPasswordView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:elevation="@dimen/biometric_dialog_elevation"
+ android:theme="?app:attr/lockPinPasswordStyle">
+
+ <include layout="@layout/auth_credential_password_pin_content_view" />
+
+</com.android.systemui.biometrics.ui.CredentialPasswordView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml b/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml
new file mode 100644
index 000000000000..11284fd2237b
--- /dev/null
+++ b/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml
@@ -0,0 +1,104 @@
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <RelativeLayout
+ android:id="@+id/auth_credential_header"
+ style="?headerStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="0dp">
+
+ <ImageView
+ android:id="@+id/icon"
+ style="?headerIconStyle"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:contentDescription="@null" />
+
+ <TextView
+ android:id="@+id/title"
+ style="?titleTextAppearance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/icon" />
+
+ <TextView
+ android:id="@+id/subtitle"
+ style="?subTitleTextAppearance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title" />
+
+ <TextView
+ android:id="@+id/description"
+ style="?descriptionTextAppearance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/subtitle" />
+
+ </RelativeLayout>
+
+ </ScrollView>
+
+ <FrameLayout
+ android:id="@+id/auth_credential_input"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:orientation="vertical">
+
+ <ImeAwareEditText
+ android:id="@+id/lockPassword"
+ style="?passwordTextAppearance"
+ android:layout_width="208dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
+ android:inputType="textPassword"
+ android:minHeight="48dp"/>
+
+ <TextView
+ android:id="@+id/error"
+ style="?errorTextAppearance"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/emergencyCallButton"
+ style="@style/AuthCredentialEmergencyButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
+ android:text="@string/work_challenge_emergency_button_text"/>
+ </FrameLayout>
+
+</merge>
diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml
index 33f1b10b123b..f8d9a87d5e54 100644
--- a/packages/SystemUI/res/layout/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml
@@ -23,71 +23,6 @@
android:orientation="vertical"
android:theme="?app:attr/lockPinPasswordStyle">
- <ScrollView
- android:id="@+id/auth_credential_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <RelativeLayout
- style="?headerStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/icon"
- style="?headerIconStyle"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:contentDescription="@null" />
-
- <TextView
- android:id="@+id/title"
- style="?titleTextAppearance"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/icon" />
-
- <TextView
- android:id="@+id/subtitle"
- style="?subTitleTextAppearance"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/title" />
-
- <TextView
- android:id="@+id/description"
- style="?descriptionTextAppearance"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/subtitle" />
-
- </RelativeLayout>
-
- </ScrollView>
-
- <LinearLayout
- android:id="@+id/auth_credential_input"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <ImeAwareEditText
- android:id="@+id/lockPassword"
- style="?passwordTextAppearance"
- android:layout_width="208dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
- android:inputType="textPassword"
- android:minHeight="48dp" />
-
- <TextView
- android:id="@+id/error"
- style="?errorTextAppearance"
- android:layout_gravity="center_horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
+ <include layout="@layout/auth_credential_password_pin_content_view" />
</com.android.systemui.biometrics.ui.CredentialPasswordView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
index 81ca37189ac4..59828fde309f 100644
--- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
@@ -58,24 +58,42 @@
android:layout_height="wrap_content"/>
</RelativeLayout>
- <FrameLayout
+ <RelativeLayout
android:id="@+id/auth_credential_container"
- style="?containerStyle"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPattern"
- android:layout_gravity="center"
- android:layout_width="@dimen/biometric_auth_pattern_view_size"
- android:layout_height="@dimen/biometric_auth_pattern_view_size"/>
+ <FrameLayout
+ android:layout_centerInParent="true"
+ android:layout_above="@id/emergencyCallButton"
+ style="?containerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_gravity="center"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"/>
- <TextView
- android:id="@+id/error"
- style="?errorTextAppearance"
- android:layout_width="match_parent"
+ <TextView
+ android:id="@+id/error"
+ style="?errorTextAppearance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"/>
+ </FrameLayout>
+
+ <Button
+ android:id="@+id/emergencyCallButton"
+ style="@style/AuthCredentialEmergencyButtonStyle"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom"/>
- </FrameLayout>
+ android:layout_alignParentBottom="true"
+ android:visibility="gone"
+ android:layout_marginBottom="35dp"
+ android:layout_centerHorizontal="true"
+ android:text="@string/work_challenge_emergency_button_text"/>
+ </RelativeLayout>
</com.android.systemui.biometrics.ui.CredentialPatternView>
diff --git a/packages/SystemUI/res/layout/auth_credential_pin_view.xml b/packages/SystemUI/res/layout/auth_credential_pin_view.xml
new file mode 100644
index 000000000000..a1cf807af088
--- /dev/null
+++ b/packages/SystemUI/res/layout/auth_credential_pin_view.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<com.android.systemui.biometrics.ui.CredentialPasswordView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:elevation="@dimen/biometric_dialog_elevation"
+ android:orientation="vertical"
+ android:theme="?app:attr/lockPinPasswordStyle">
+
+ <include layout="@layout/auth_credential_password_pin_content_view" />
+
+</com.android.systemui.biometrics.ui.CredentialPasswordView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index f14be410bf75..ec006c553b94 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -416,11 +416,22 @@
android:focusable="true"/>
</LinearLayout>
- <LinearLayout
+ <RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_gravity="end|center_vertical">
+ android:gravity="center_vertical">
+ <Button
+ android:id="@+id/share_wifi_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/share_wifi_button_text"
+ style="?android:attr/buttonBarNeutralButtonStyle"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:clickable="true"
+ android:focusable="true"
+ android:layout_alignParentLeft="true"
+ android:visibility="gone"/>
<Button
android:id="@+id/done_button"
android:layout_width="wrap_content"
@@ -430,8 +441,9 @@
android:maxLines="1"
android:ellipsize="end"
android:clickable="true"
- android:focusable="true"/>
- </LinearLayout>
+ android:focusable="true"
+ android:layout_alignParentRight="true"/>
+ </RelativeLayout>
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
index 78cd7184b485..39ec09b14157 100644
--- a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
+++ b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
@@ -34,8 +34,8 @@
android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
android:contentDescription="@string/screenshot_dismiss_work_profile">
<ImageView
- android:layout_width="16dp"
- android:layout_height="16dp"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
android:layout_gravity="center"
android:background="@drawable/circular_background"
android:backgroundTint="?androidprv:attr/materialColorSurfaceContainerHigh"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index d693631080af..8bc3eed59062 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -221,6 +221,7 @@
<attr name="descriptionTextAppearance" format="reference" />
<attr name="passwordTextAppearance" format="reference" />
<attr name="errorTextAppearance" format="reference"/>
+ <attr name="errorTextAppearanceLand" format="reference"/>
</declare-styleable>
<declare-styleable name="LogAccessPermissionGrantDialog">
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 4e72518bc613..04eae64013b3 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -222,4 +222,13 @@
<!-- Communal mode -->
<item type="id" name="communal_widget_wrapper" />
+
+ <!-- Values assigned to the views in Biometrics Prompt -->
+ <item type="id" name="pin_pad"/>
+
+ <!--
+ Used to tag views programmatically added to the smartspace area so they can be more easily
+ removed later.
+ -->
+ <item type="id" name="tag_smartspace_view" />
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index cddfda2f9ce7..77ffe193c98f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -156,6 +156,9 @@
<!-- Button label for declining language change [CHAR LIMIT=25] -->
<string name="hdmi_cec_set_menu_language_decline">Keep current language</string>
+ <!-- Button label to share wifi [CHAR_LIMIT=20] -->
+ <string name="share_wifi_button_text">Share Wi\u2011Fi</string>
+
<!-- Title of confirmation dialog for wireless debugging [CHAR LIMIT=NONE] -->
<string name="wifi_debugging_title">Allow wireless debugging on this network?</string>
@@ -386,6 +389,8 @@
<string name="biometric_dialog_wrong_password">Wrong password</string>
<!-- Error string shown when the user enters too many incorrect attempts [CHAR LIMIT=120]-->
<string name="biometric_dialog_credential_too_many_attempts">Too many incorrect attempts.\nTry again in <xliff:g id="number">%d</xliff:g> seconds.</string>
+ <!-- Button text shown on an authentication screen giving the user the option to make an emergency call without unlocking their device [CHAR LIMIT=20] -->
+ <string name="work_challenge_emergency_button_text">Emergency</string>
<!-- Error string shown when the user enters an incorrect PIN/pattern/password and it counts towards the max attempts before the data on the device is wiped. [CHAR LIMIT=NONE]-->
<string name="biometric_dialog_credential_attempts_before_wipe">Try again. Attempt <xliff:g id="attempts" example="1">%1$d</xliff:g> of <xliff:g id="max_attempts" example="3">%2$d</xliff:g>.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 10340c6847f7..6991b964c504 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -236,6 +236,13 @@
<item name="android:gravity">center</item>
</style>
+ <style name="TextAppearance.AuthNonBioCredential.ErrorLand">
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/colorError</item>
+ <item name="android:gravity">start</item>
+ </style>
+
<style name="TextAppearance.AuthCredential.PasswordEntry" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:gravity">center</item>
<item name="android:paddingTop">28dp</item>
@@ -276,6 +283,17 @@
<item name="android:minWidth">200dp</item>
</style>
+ <style name="AuthCredentialEmergencyButtonStyle">
+ <item name="android:background">@drawable/auth_credential_emergency_button_background</item>
+ <item name="android:textColor">@android:color/system_accent3_900</item>
+ <item name="android:outlineProvider">none</item>
+ <item name="android:paddingTop">15dp</item>
+ <item name="android:paddingBottom">15dp</item>
+ <item name="android:paddingLeft">30dp</item>
+ <item name="android:paddingRight">30dp</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
<style name="DeviceManagementDialogTitle">
<item name="android:gravity">center</item>
<item name="android:textAppearance">@style/TextAppearance.Dialog.Title</item>
@@ -353,6 +371,7 @@
<item name="descriptionTextAppearance">@style/TextAppearance.AuthNonBioCredential.Description</item>
<item name="passwordTextAppearance">@style/TextAppearance.AuthCredential.PasswordEntry</item>
<item name="errorTextAppearance">@style/TextAppearance.AuthNonBioCredential.Error</item>
+ <item name="errorTextAppearanceLand">@style/TextAppearance.AuthNonBioCredential.ErrorLand</item>
</style>
<style name="LockPatternViewStyle" >
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 45a5ce34f830..80040a384b9d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -200,11 +200,12 @@ public class ActivityManagerWrapper {
@Override
public void onAnimationStart(IRecentsAnimationController controller,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
- Rect homeContentInsets, Rect minimizedHomeBounds) {
+ Rect homeContentInsets, Rect minimizedHomeBounds,
+ Bundle extras) {
final RecentsAnimationControllerCompat controllerCompat =
new RecentsAnimationControllerCompat(controller);
animationHandler.onAnimationStart(controllerCompat, apps,
- wallpapers, homeContentInsets, minimizedHomeBounds);
+ wallpapers, homeContentInsets, minimizedHomeBounds, extras);
}
@Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index 8bddf217ccb4..24073501c946 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -17,6 +17,7 @@
package com.android.systemui.shared.system;
import android.graphics.Rect;
+import android.os.Bundle;
import android.view.RemoteAnimationTarget;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -29,7 +30,7 @@ public interface RecentsAnimationListener {
*/
void onAnimationStart(RecentsAnimationControllerCompat controller,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
- Rect homeContentInsets, Rect minimizedHomeBounds);
+ Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras);
/**
* Called when the animation into Recents was canceled. This call is made on the binder thread.
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
index f005bab55de6..fae9fec0c26d 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -33,8 +33,7 @@ import javax.inject.Named
SettingsUtilModule::class,
])
abstract class FlagsModule {
- @Binds
- abstract fun bindsFeatureFlagDebug(impl: FeatureFlagsDebug): FeatureFlags
+ @Binds abstract fun bindsFeatureFlagDebug(impl: FeatureFlagsClassicDebug): FeatureFlagsClassic
@Binds
@IntoSet
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
index 927d4604b823..7aacb4efba8e 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
@@ -29,7 +29,7 @@ import javax.inject.Named
])
abstract class FlagsModule {
@Binds
- abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
+ abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsClassicRelease): FeatureFlagsClassic
@Binds
@IntoSet
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index dd39f1d6ed28..6d2880e00203 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -222,8 +222,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
- mDumpManager.unregisterDumpable(getClass().getSimpleName()); // unregister previous clocks
- mDumpManager.registerDumpable(getClass().getSimpleName(), this);
+ if (!mOnlyClock) {
+ mDumpManager.unregisterDumpable(getClass().getSimpleName()); // unregister previous
+ mDumpManager.registerDumpable(getClass().getSimpleName(), this);
+ }
if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
mStatusArea = mView.findViewById(R.id.keyguard_status_area);
@@ -291,7 +293,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
int viewIndex = mStatusArea.indexOfChild(ksv);
ksv.setVisibility(View.GONE);
- mSmartspaceController.removeViewsFromParent(mStatusArea);
+ removeViewsFromStatusArea();
addSmartspaceView();
// TODO(b/261757708): add content observer for the Settings toggle and add/remove
// weather according to the Settings.
@@ -323,7 +325,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
void onLocaleListChanged() {
if (mSmartspaceController.isEnabled()) {
- mSmartspaceController.removeViewsFromParent(mStatusArea);
+ removeViewsFromStatusArea();
addSmartspaceView();
if (mSmartspaceController.isDateWeatherDecoupled()) {
mDateWeatherView.removeView(mWeatherView);
@@ -618,4 +620,13 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
return ((mCurrentClockSize == LARGE) ? clock.getLargeClock() : clock.getSmallClock())
.getConfig().getHasCustomWeatherDataDisplay();
}
+
+ private void removeViewsFromStatusArea() {
+ for (int i = mStatusArea.getChildCount() - 1; i >= 0; i--) {
+ final View childView = mStatusArea.getChildAt(i);
+ if (childView.getTag(R.id.tag_smartspace_view) != null) {
+ mStatusArea.removeViewAt(i);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 58c8000a2328..7464c8803c99 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -73,9 +73,7 @@ import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteracto
import com.android.systemui.biometrics.domain.model.BiometricModalities;
import com.android.systemui.biometrics.ui.BiometricPromptLayout;
import com.android.systemui.biometrics.ui.CredentialView;
-import com.android.systemui.biometrics.ui.binder.AuthBiometricFingerprintViewBinder;
import com.android.systemui.biometrics.ui.binder.BiometricViewBinder;
-import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.dagger.qualifiers.Background;
@@ -142,8 +140,6 @@ public class AuthContainerView extends LinearLayout
// TODO: these should be migrated out once ready
private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor;
- private final Provider<AuthBiometricFingerprintViewModel>
- mAuthBiometricFingerprintViewModelProvider;
private final @NonNull Provider<PromptSelectorInteractor> mPromptSelectorInteractorProvider;
// TODO(b/251476085): these should be migrated out of the view
private final Provider<CredentialViewModel> mCredentialViewModelProvider;
@@ -283,8 +279,6 @@ public class AuthContainerView extends LinearLayout
@NonNull UserManager userManager,
@NonNull LockPatternUtils lockPatternUtils,
@NonNull InteractionJankMonitor jankMonitor,
- @NonNull Provider<AuthBiometricFingerprintViewModel>
- authBiometricFingerprintViewModelProvider,
@NonNull Provider<PromptCredentialInteractor> promptCredentialInteractor,
@NonNull Provider<PromptSelectorInteractor> promptSelectorInteractor,
@NonNull PromptViewModel promptViewModel,
@@ -293,9 +287,9 @@ public class AuthContainerView extends LinearLayout
@NonNull VibratorHelper vibratorHelper) {
this(config, featureFlags, applicationCoroutineScope, fpProps, faceProps,
wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils,
- jankMonitor, authBiometricFingerprintViewModelProvider, promptSelectorInteractor,
- promptCredentialInteractor, promptViewModel, credentialViewModelProvider,
- new Handler(Looper.getMainLooper()), bgExecutor, vibratorHelper);
+ jankMonitor, promptSelectorInteractor, promptCredentialInteractor, promptViewModel,
+ credentialViewModelProvider, new Handler(Looper.getMainLooper()), bgExecutor,
+ vibratorHelper);
}
@VisibleForTesting
@@ -309,8 +303,6 @@ public class AuthContainerView extends LinearLayout
@NonNull UserManager userManager,
@NonNull LockPatternUtils lockPatternUtils,
@NonNull InteractionJankMonitor jankMonitor,
- @NonNull Provider<AuthBiometricFingerprintViewModel>
- authBiometricFingerprintViewModelProvider,
@NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
@NonNull Provider<PromptCredentialInteractor> credentialInteractor,
@NonNull PromptViewModel promptViewModel,
@@ -359,7 +351,6 @@ public class AuthContainerView extends LinearLayout
mBackgroundExecutor = bgExecutor;
mInteractionJankMonitor = jankMonitor;
mPromptCredentialInteractor = credentialInteractor;
- mAuthBiometricFingerprintViewModelProvider = authBiometricFingerprintViewModelProvider;
mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
mCredentialViewModelProvider = credentialViewModelProvider;
mPromptViewModel = promptViewModel;
@@ -442,9 +433,6 @@ public class AuthContainerView extends LinearLayout
fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
fingerprintAndFaceView.setFaceClass3(
faceProperties.sensorStrength == STRENGTH_STRONG);
- final AuthBiometricFingerprintViewModel fpAndFaceViewModel =
- mAuthBiometricFingerprintViewModelProvider.get();
- AuthBiometricFingerprintViewBinder.bind(fingerprintAndFaceView, fpAndFaceViewModel);
mBiometricView = fingerprintAndFaceView;
} else if (fpProperties != null) {
final AuthBiometricFingerprintView fpView =
@@ -453,9 +441,6 @@ public class AuthContainerView extends LinearLayout
fpView.setSensorProperties(fpProperties);
fpView.setScaleFactorProvider(config.mScaleProvider);
fpView.updateOverrideIconLayoutParamsSize();
- final AuthBiometricFingerprintViewModel fpViewModel =
- mAuthBiometricFingerprintViewModelProvider.get();
- AuthBiometricFingerprintViewBinder.bind(fpView, fpViewModel);
mBiometricView = fpView;
} else if (faceProperties != null) {
mBiometricView = (AuthBiometricFaceView) layoutInflater.inflate(
@@ -514,6 +499,8 @@ public class AuthContainerView extends LinearLayout
R.layout.auth_credential_pattern_view, null, false);
break;
case Utils.CREDENTIAL_PIN:
+ mCredentialView = factory.inflate(R.layout.auth_credential_pin_view, null, false);
+ break;
case Utils.CREDENTIAL_PASSWORD:
mCredentialView = factory.inflate(
R.layout.auth_credential_password_view, null, false);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 7b288a8d49f1..d5289a49be51 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -73,7 +73,6 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
-import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.dagger.SysUISingleton;
@@ -134,8 +133,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
private final CoroutineScope mApplicationCoroutineScope;
// TODO: these should be migrated out once ready
- @NonNull private final Provider<AuthBiometricFingerprintViewModel>
- mAuthBiometricFingerprintViewModelProvider;
@NonNull private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor;
@NonNull private final Provider<PromptSelectorInteractor> mPromptSelectorInteractor;
@NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider;
@@ -765,8 +762,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
@NonNull LockPatternUtils lockPatternUtils,
@NonNull UdfpsLogger udfpsLogger,
@NonNull LogContextInteractor logContextInteractor,
- @NonNull Provider<AuthBiometricFingerprintViewModel>
- authBiometricFingerprintViewModelProvider,
@NonNull Provider<PromptCredentialInteractor> promptCredentialInteractorProvider,
@NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider,
@NonNull Provider<CredentialViewModel> credentialViewModelProvider,
@@ -801,7 +796,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mVibratorHelper = vibratorHelper;
mLogContextInteractor = logContextInteractor;
- mAuthBiometricFingerprintViewModelProvider = authBiometricFingerprintViewModelProvider;
mPromptSelectorInteractor = promptSelectorInteractorProvider;
mPromptCredentialInteractor = promptCredentialInteractorProvider;
mPromptViewModelProvider = promptViewModelProvider;
@@ -1344,9 +1338,8 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
config.mScaleProvider = this::getScaleFactor;
return new AuthContainerView(config, mFeatureFlags, mApplicationCoroutineScope, mFpProps, mFaceProps,
wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils,
- mInteractionJankMonitor, mAuthBiometricFingerprintViewModelProvider,
- mPromptCredentialInteractor, mPromptSelectorInteractor, viewModel,
- mCredentialViewModelProvider, bgExecutor, mVibratorHelper);
+ mInteractionJankMonitor, mPromptCredentialInteractor, mPromptSelectorInteractor,
+ viewModel, mCredentialViewModelProvider, bgExecutor, mVibratorHelper);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt
index 20c3e4098e83..f7f910391566 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt
@@ -56,10 +56,10 @@ interface UdfpsModule {
)
)
} else {
- BoundingBoxOverlapDetector()
+ BoundingBoxOverlapDetector(values[2])
}
} else {
- return BoundingBoxOverlapDetector()
+ return BoundingBoxOverlapDetector(1f)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index bb87dca1cdc4..5badcaf06003 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -21,15 +21,18 @@ import com.android.internal.widget.LockPatternUtils
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.Utils.getCredentialType
import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed
+import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.PromptRepository
import com.android.systemui.biometrics.domain.model.BiometricModalities
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -65,6 +68,9 @@ interface PromptSelectorInteractor {
*/
val isConfirmationRequired: Flow<Boolean>
+ /** Fingerprint sensor type */
+ val sensorType: StateFlow<FingerprintSensorType>
+
/** Use biometrics for authentication. */
fun useBiometricsForAuthentication(
promptInfo: PromptInfo,
@@ -89,6 +95,7 @@ interface PromptSelectorInteractor {
class PromptSelectorInteractorImpl
@Inject
constructor(
+ private val fingerprintPropertyRepository: FingerprintPropertyRepository,
private val promptRepository: PromptRepository,
lockPatternUtils: LockPatternUtils,
) : PromptSelectorInteractor {
@@ -140,6 +147,9 @@ constructor(
}
}
+ override val sensorType: StateFlow<FingerprintSensorType> =
+ fingerprintPropertyRepository.sensorType
+
override fun useBiometricsForAuthentication(
promptInfo: PromptInfo,
userId: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
index caebc30d1c07..a3ee220d3c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
@@ -16,6 +16,7 @@ sealed class BiometricPromptRequest(
val description: String,
val userInfo: BiometricUserInfo,
val operationInfo: BiometricOperationInfo,
+ val showEmergencyCallButton: Boolean,
) {
/** Prompt using one or more biometrics. */
class Biometric(
@@ -29,7 +30,8 @@ sealed class BiometricPromptRequest(
subtitle = info.subtitle?.toString() ?: "",
description = info.description?.toString() ?: "",
userInfo = userInfo,
- operationInfo = operationInfo
+ operationInfo = operationInfo,
+ showEmergencyCallButton = info.isShowEmergencyCallButton
) {
val negativeButtonText: String = info.negativeButtonText?.toString() ?: ""
}
@@ -46,6 +48,7 @@ sealed class BiometricPromptRequest(
description = (info.deviceCredentialDescription ?: info.description)?.toString() ?: "",
userInfo = userInfo,
operationInfo = operationInfo,
+ showEmergencyCallButton = info.isShowEmergencyCallButton
) {
/** PIN prompt. */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt
index cf6044f146b0..9b946db0daf0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt
@@ -17,16 +17,30 @@
package com.android.systemui.biometrics.udfps
import android.graphics.Rect
+import android.os.Build
+import android.util.Log
import com.android.systemui.dagger.SysUISingleton
/** Returns whether the touch coordinates are within the sensor's bounding box. */
@SysUISingleton
-class BoundingBoxOverlapDetector : OverlapDetector {
+class BoundingBoxOverlapDetector(private val targetSize: Float) : OverlapDetector {
+
+ private val TAG = "BoundingBoxOverlapDetector"
+
override fun isGoodOverlap(
touchData: NormalizedTouchData,
nativeSensorBounds: Rect,
nativeOverlayBounds: Rect,
- ): Boolean =
- touchData.isWithinBounds(nativeOverlayBounds) &&
- touchData.isWithinBounds(nativeSensorBounds)
+ ): Boolean {
+ val scaledRadius = (nativeSensorBounds.width() / 2) * targetSize
+ val scaledSensorBounds =
+ Rect(
+ (nativeSensorBounds.centerX() - scaledRadius).toInt(),
+ (nativeSensorBounds.centerY() - scaledRadius).toInt(),
+ (nativeSensorBounds.centerX() + scaledRadius).toInt(),
+ (nativeSensorBounds.centerY() + scaledRadius).toInt(),
+ )
+
+ return touchData.isWithinBounds(scaledSensorBounds)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
index 709fe855fbfc..6c5cc4835787 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
@@ -8,11 +8,8 @@ import android.view.View
import android.view.WindowInsets
import android.view.WindowInsets.Type.ime
import android.view.accessibility.AccessibilityManager
-import android.widget.ImageView
-import android.widget.ImeAwareEditText
import android.widget.LinearLayout
import android.widget.TextView
-import androidx.core.view.isGone
import com.android.systemui.R
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.binder.CredentialViewBinder
@@ -22,14 +19,6 @@ import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
class CredentialPasswordView(context: Context, attrs: AttributeSet?) :
LinearLayout(context, attrs), CredentialView, View.OnApplyWindowInsetsListener {
- private lateinit var titleView: TextView
- private lateinit var subtitleView: TextView
- private lateinit var descriptionView: TextView
- private lateinit var iconView: ImageView
- private lateinit var passwordField: ImeAwareEditText
- private lateinit var credentialHeader: View
- private lateinit var credentialInput: View
-
private var bottomInset: Int = 0
private val accessibilityManager by lazy {
@@ -48,90 +37,32 @@ class CredentialPasswordView(context: Context, attrs: AttributeSet?) :
override fun onFinishInflate() {
super.onFinishInflate()
-
- titleView = requireViewById(R.id.title)
- subtitleView = requireViewById(R.id.subtitle)
- descriptionView = requireViewById(R.id.description)
- iconView = requireViewById(R.id.icon)
- passwordField = requireViewById(R.id.lockPassword)
- credentialHeader = requireViewById(R.id.auth_credential_header)
- credentialInput = requireViewById(R.id.auth_credential_input)
-
setOnApplyWindowInsetsListener(this)
}
- override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
- super.onLayout(changed, left, top, right, bottom)
-
- val inputLeftBound: Int
- var inputTopBound: Int
- var headerRightBound = right
- var headerTopBounds = top
- var headerBottomBounds = bottom
- val subTitleBottom: Int = if (subtitleView.isGone) titleView.bottom else subtitleView.bottom
- val descBottom = if (descriptionView.isGone) subTitleBottom else descriptionView.bottom
- if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) {
- inputTopBound = (bottom - credentialInput.height) / 2
- inputLeftBound = (right - left) / 2
- headerRightBound = inputLeftBound
- if (descriptionView.bottom > headerBottomBounds) {
- headerTopBounds -= iconView.bottom.coerceAtMost(bottomInset)
- credentialHeader.layout(left, headerTopBounds, headerRightBound, bottom)
- }
- } else {
- inputTopBound = descBottom + (bottom - descBottom - credentialInput.height) / 2
- inputLeftBound = (right - left - credentialInput.width) / 2
-
- if (bottom - inputTopBound < credentialInput.height) {
- inputTopBound = bottom - credentialInput.height
- }
-
- if (descriptionView.bottom > inputTopBound) {
- credentialHeader.layout(left, headerTopBounds, headerRightBound, inputTopBound)
- }
- }
-
- credentialInput.layout(inputLeftBound, inputTopBound, right, bottom)
- }
-
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
-
- val newWidth = MeasureSpec.getSize(widthMeasureSpec)
- val newHeight = MeasureSpec.getSize(heightMeasureSpec) - bottomInset
-
- setMeasuredDimension(newWidth, newHeight)
-
- val halfWidthSpec = MeasureSpec.makeMeasureSpec(width / 2, MeasureSpec.AT_MOST)
- val fullHeightSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.UNSPECIFIED)
- if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) {
- measureChildren(halfWidthSpec, fullHeightSpec)
- } else {
- measureChildren(widthMeasureSpec, fullHeightSpec)
- }
- }
-
override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets {
- val bottomInsets = insets.getInsets(ime())
- if (bottomInset != bottomInsets.bottom) {
- bottomInset = bottomInsets.bottom
-
- if (bottomInset > 0 && resources.configuration.orientation == ORIENTATION_LANDSCAPE) {
- titleView.isSingleLine = true
- titleView.ellipsize = TextUtils.TruncateAt.MARQUEE
- titleView.marqueeRepeatLimit = -1
- // select to enable marquee unless a screen reader is enabled
- titleView.isSelected = accessibilityManager?.shouldMarquee() ?: false
- } else {
- titleView.isSingleLine = false
- titleView.ellipsize = null
- // select to enable marquee unless a screen reader is enabled
- titleView.isSelected = false
+ val imeBottomInset = insets.getInsets(ime()).bottom
+ if (bottomInset != imeBottomInset) {
+ val titleView: TextView? = findViewById(R.id.title)
+ if (titleView != null) {
+ if (
+ bottomInset > 0 && resources.configuration.orientation == ORIENTATION_LANDSCAPE
+ ) {
+ titleView.isSingleLine = true
+ titleView.ellipsize = TextUtils.TruncateAt.MARQUEE
+ titleView.marqueeRepeatLimit = -1
+ // select to enable marquee unless a screen reader is enabled
+ titleView.isSelected = accessibilityManager.shouldMarquee()
+ } else {
+ titleView.isSingleLine = false
+ titleView.ellipsize = null
+ // select to enable marquee unless a screen reader is enabled
+ titleView.isSelected = false
+ }
}
-
- requestLayout()
}
- return insets
+ setPadding(paddingLeft, paddingTop, paddingRight, imeBottomInset)
+ return insets.inset(0, 0, 0, imeBottomInset)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/IPinPad.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/IPinPad.kt
new file mode 100644
index 000000000000..cf6865c0fe8e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/IPinPad.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.ui
+
+/**
+ * Interface for PinPad in auth_credential_pin_view. This is needed when a custom pin pad is
+ * preferred to the IME To use a PinPad, one needs to implement IPinPad interface and provide it in
+ * auth_credential_pin_view and specify the id as [pin_pad]
+ */
+interface IPinPad {
+ fun setPinPadClickListener(pinPadClickListener: PinPadClickListener)
+}
+
+/** The call back interface for onClick event in the view. */
+interface PinPadClickListener {
+ /**
+ * One of the digit key has been clicked.
+ *
+ * @param digit A String representing a digit between 0 and 9.
+ */
+ fun onDigitKeyClick(digit: String?)
+
+ /** The backspace key has been clicked. */
+ fun onBackspaceClick()
+
+ /** The enter key has been clicked. */
+ fun onEnterKeyClick()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index d054751b760b..b1439fd7421d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -108,6 +108,9 @@ object BiometricViewBinder {
val iconViewOverlay = view.requireViewById<LottieAnimationView>(R.id.biometric_icon_overlay)
val iconView = view.requireViewById<LottieAnimationView>(R.id.biometric_icon)
+
+ PromptFingerprintIconViewBinder.bind(iconView, viewModel.fingerprintIconViewModel)
+
val indicatorMessageView = view.requireViewById<TextView>(R.id.indicator)
// Negative-side (left) buttons
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
index c27d71522c2f..996b62e084cb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
@@ -15,6 +15,7 @@ import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R
import com.android.systemui.biometrics.ui.CredentialPasswordView
import com.android.systemui.biometrics.ui.CredentialView
+import com.android.systemui.biometrics.ui.IPinPad
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import kotlinx.coroutines.awaitCancellation
@@ -53,13 +54,19 @@ object CredentialPasswordViewBinder {
}
)
passwordField.setOnKeyListener(OnBackButtonListener(onBackInvokedCallback))
-
+ val pinPadView = view.findViewById(R.id.pin_pad) as? IPinPad
+ if (pinPadView != null) {
+ PinPadViewBinder.bind(pinPadView, view)
+ }
repeatOnLifecycle(Lifecycle.State.STARTED) {
// dismiss on a valid credential check
launch {
viewModel.validatedAttestation.collect { attestation ->
if (attestation != null) {
- imeManager.hideSoftInputFromWindow(view.windowToken, 0 /* flags */)
+ imeManager.hideSoftInputFromWindow(
+ view.windowToken,
+ 0 // flag
+ )
host.onCredentialMatched(attestation)
} else {
passwordField.setText("")
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index 9292bd7ecd60..25fe61916644 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -2,6 +2,7 @@ package com.android.systemui.biometrics.ui.binder
import android.view.View
import android.view.ViewGroup
+import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.Lifecycle
@@ -46,6 +47,8 @@ object CredentialViewBinder {
val descriptionView: TextView = view.requireViewById(R.id.description)
val iconView: ImageView? = view.findViewById(R.id.icon)
val errorView: TextView = view.requireViewById(R.id.error)
+ val cancelButton: Button? = view.findViewById(R.id.cancel_button)
+ val emergencyButtonView: Button = view.requireViewById(R.id.emergencyCallButton)
var errorTimer: Job? = null
@@ -58,7 +61,7 @@ object CredentialViewBinder {
updateForContentDimensions(
containerWidth,
containerHeight,
- 0 /* animateDurationMs */
+ 0 // animateDurationMs
)
}
}
@@ -75,6 +78,13 @@ object CredentialViewBinder {
iconView?.setImageDrawable(header.icon)
+ if (header.showEmergencyCallButton) {
+ emergencyButtonView.visibility = View.VISIBLE
+ emergencyButtonView.setOnClickListener {
+ viewModel.doEmergencyCall(view.context)
+ }
+ }
+
// Only animate this if we're transitioning from a biometric view.
if (viewModel.animateContents.value) {
view.animateCredentialViewIn()
@@ -94,7 +104,18 @@ object CredentialViewBinder {
}
}
}
- .collect { errorView.textOrHide = it }
+ .collect { it ->
+ val hasError = !it.isNullOrBlank()
+ errorView.visibility =
+ if (hasError) {
+ View.VISIBLE
+ } else if (cancelButton != null) {
+ View.INVISIBLE
+ } else {
+ View.GONE
+ }
+ errorView.text = if (hasError) it else ""
+ }
}
// show an extra dialog if the remaining attempts becomes low
@@ -108,6 +129,8 @@ object CredentialViewBinder {
}
}
+ cancelButton?.setOnClickListener { host.onCredentialAborted() }
+
// bind the auth widget
when (view) {
is CredentialPasswordView ->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PinPadViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PinPadViewBinder.kt
new file mode 100644
index 000000000000..906206c27455
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PinPadViewBinder.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.biometrics.ui.binder
+
+import android.view.KeyEvent
+import android.widget.ImeAwareEditText
+import com.android.internal.widget.LockscreenCredential
+import com.android.systemui.R
+import com.android.systemui.biometrics.ui.CredentialPasswordView
+import com.android.systemui.biometrics.ui.IPinPad
+import com.android.systemui.biometrics.ui.PinPadClickListener
+
+/** Binder for IPinPad */
+object PinPadViewBinder {
+ /** Implements a PinPadClickListener inside a pin pad */
+ @JvmStatic
+ fun bind(view: IPinPad, credentialPasswordView: CredentialPasswordView) {
+ val passwordField: ImeAwareEditText =
+ credentialPasswordView.requireViewById(R.id.lockPassword)
+ view.setPinPadClickListener(
+ object : PinPadClickListener {
+
+ override fun onDigitKeyClick(digit: String?) {
+ passwordField.append(digit)
+ }
+
+ override fun onBackspaceClick() {
+ val pin = LockscreenCredential.createPinOrNone(passwordField.text)
+ if (pin.size() > 0) {
+ passwordField.text.delete(
+ passwordField.selectionEnd - 1,
+ passwordField.selectionEnd
+ )
+ }
+ pin.zeroize()
+ }
+
+ override fun onEnterKeyClick() {
+ passwordField.dispatchKeyEvent(
+ KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0)
+ )
+ passwordField.dispatchKeyEvent(
+ KeyEvent(0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0)
+ )
+ }
+ }
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt
index bd0907e588ca..188c82b52374 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt
@@ -21,26 +21,29 @@ import android.view.DisplayInfo
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView
-import com.android.systemui.biometrics.AuthBiometricFingerprintView
-import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel
+import com.android.systemui.biometrics.ui.viewmodel.PromptFingerprintIconViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import kotlinx.coroutines.launch
-/** Sub-binder for [AuthBiometricFingerprintView.mIconView]. */
-object AuthBiometricFingerprintIconViewBinder {
+/** Sub-binder for [BiometricPromptLayout.iconView]. */
+object PromptFingerprintIconViewBinder {
- /**
- * Binds a [AuthBiometricFingerprintView.mIconView] to a [AuthBiometricFingerprintViewModel].
- */
+ /** Binds [BiometricPromptLayout.iconView] to [PromptFingerprintIconViewModel]. */
@JvmStatic
- fun bind(view: LottieAnimationView, viewModel: AuthBiometricFingerprintViewModel) {
+ fun bind(view: LottieAnimationView, viewModel: PromptFingerprintIconViewModel) {
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
val displayInfo = DisplayInfo()
view.context.display?.getDisplayInfo(displayInfo)
viewModel.setRotation(displayInfo.rotation)
viewModel.onConfigurationChanged(view.context.resources.configuration)
- launch { viewModel.iconAsset.collect { iconAsset -> view.setAnimation(iconAsset) } }
+ launch {
+ viewModel.iconAsset.collect { iconAsset ->
+ if (iconAsset != -1) {
+ view.setAnimation(iconAsset)
+ }
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
index 3257f20815d8..c6d90855e7d2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
@@ -10,4 +10,5 @@ interface CredentialHeaderViewModel {
val subtitle: String
val description: String
val icon: Drawable
+ val showEmergencyCallButton: Boolean
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
index a3b23ca89cad..6212ef000ff1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
@@ -41,6 +41,7 @@ constructor(
subtitle = request.subtitle,
description = request.description,
icon = applicationContext.asLockIcon(request.userInfo.deviceCredentialOwnerId),
+ showEmergencyCallButton = request.showEmergencyCallButton
)
}
@@ -136,6 +137,18 @@ constructor(
}
}
}
+
+ fun doEmergencyCall(context: Context) {
+ val intent =
+ context
+ .getSystemService(android.telecom.TelecomManager::class.java)!!
+ .createLaunchEmergencyDialerIntent(null)
+ .setFlags(
+ android.content.Intent.FLAG_ACTIVITY_NEW_TASK or
+ android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
+ )
+ context.startActivity(intent)
+ }
}
private fun Context.asBadCredentialErrorMessage(prompt: BiometricPromptRequest?): String =
@@ -174,6 +187,7 @@ private class BiometricPromptHeaderViewModelImpl(
override val subtitle: String,
override val description: String,
override val icon: Drawable,
+ override val showEmergencyCallButton: Boolean,
) : CredentialHeaderViewModel
private fun CredentialHeaderViewModel.asRequest(): BiometricPromptRequest.Credential =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
index 617d80cee09d..9b30acb84428 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
@@ -22,23 +22,35 @@ import android.content.res.Configuration
import android.view.Surface
import com.android.systemui.R
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
-/** Models UI of AuthBiometricFingerprintView to support rear display state changes. */
-class AuthBiometricFingerprintViewModel
+/** Models UI of [BiometricPromptLayout.iconView] */
+class PromptFingerprintIconViewModel
@Inject
-constructor(private val interactor: DisplayStateInteractor) {
+constructor(
+ private val displayStateInteractor: DisplayStateInteractor,
+ private val promptSelectorInteractor: PromptSelectorInteractor,
+) {
/** Current device rotation. */
private var rotation: Int = Surface.ROTATION_0
- /** Current AuthBiometricFingerprintView asset. */
+ /** Current BiometricPromptLayout.iconView asset. */
val iconAsset: Flow<Int> =
- combine(interactor.isFolded, interactor.isInRearDisplayMode) {
- isFolded: Boolean,
- isInRearDisplayMode: Boolean ->
- getSideFpsAnimationAsset(isFolded, isInRearDisplayMode)
+ combine(
+ displayStateInteractor.isFolded,
+ displayStateInteractor.isInRearDisplayMode,
+ promptSelectorInteractor.sensorType,
+ ) { isFolded: Boolean, isInRearDisplayMode: Boolean, sensorType: FingerprintSensorType ->
+ when (sensorType) {
+ FingerprintSensorType.POWER_BUTTON ->
+ getSideFpsAnimationAsset(isFolded, isInRearDisplayMode)
+ // Replace below when non-SFPS iconAsset logic is migrated to this ViewModel
+ else -> -1
+ }
}
@RawRes
@@ -75,7 +87,7 @@ constructor(private val interactor: DisplayStateInteractor) {
/** Called on configuration changes */
fun onConfigurationChanged(newConfig: Configuration) {
- interactor.onConfigurationChanged(newConfig)
+ displayStateInteractor.onConfigurationChanged(newConfig)
}
fun setRotation(newRotation: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 89561a5a212b..4dc7720ef447 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -20,6 +20,7 @@ import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import com.android.systemui.biometrics.AuthBiometricView
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
@@ -45,16 +46,23 @@ import kotlinx.coroutines.launch
class PromptViewModel
@Inject
constructor(
- private val interactor: PromptSelectorInteractor,
+ private val displayStateInteractor: DisplayStateInteractor,
+ private val promptSelectorInteractor: PromptSelectorInteractor,
private val vibrator: VibratorHelper,
private val featureFlags: FeatureFlags,
) {
+ /** Models UI of [BiometricPromptLayout.iconView] */
+ val fingerprintIconViewModel: PromptFingerprintIconViewModel =
+ PromptFingerprintIconViewModel(displayStateInteractor, promptSelectorInteractor)
+
/** The set of modalities available for this prompt */
val modalities: Flow<BiometricModalities> =
- interactor.prompt.map { it?.modalities ?: BiometricModalities() }.distinctUntilChanged()
+ promptSelectorInteractor.prompt
+ .map { it?.modalities ?: BiometricModalities() }
+ .distinctUntilChanged()
// TODO(b/251476085): remove after icon controllers are migrated - do not keep this state
- private var _legacyState = MutableStateFlow(AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN)
+ private var _legacyState = MutableStateFlow(AuthBiometricView.STATE_IDLE)
val legacyState: StateFlow<Int> = _legacyState.asStateFlow()
private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false)
@@ -75,17 +83,18 @@ constructor(
* successful authentication.
*/
val isConfirmationRequired: Flow<Boolean> =
- combine(_isOverlayTouched, interactor.isConfirmationRequired) {
+ combine(_isOverlayTouched, promptSelectorInteractor.isConfirmationRequired) {
isOverlayTouched,
isConfirmationRequired ->
!isOverlayTouched && isConfirmationRequired
}
/** The kind of credential the user has. */
- val credentialKind: Flow<PromptKind> = interactor.credentialKind
+ val credentialKind: Flow<PromptKind> = promptSelectorInteractor.credentialKind
/** The label to use for the cancel button. */
- val negativeButtonText: Flow<String> = interactor.prompt.map { it?.negativeButtonText ?: "" }
+ val negativeButtonText: Flow<String> =
+ promptSelectorInteractor.prompt.map { it?.negativeButtonText ?: "" }
private val _message: MutableStateFlow<PromptMessage> = MutableStateFlow(PromptMessage.Empty)
@@ -113,7 +122,7 @@ constructor(
_forceLargeSize,
_forceMediumSize,
modalities,
- interactor.isConfirmationRequired,
+ promptSelectorInteractor.isConfirmationRequired,
fingerprintStartMode,
) { forceLarge, forceMedium, modalities, confirmationRequired, fpStartMode ->
when {
@@ -129,14 +138,16 @@ constructor(
.distinctUntilChanged()
/** Title for the prompt. */
- val title: Flow<String> = interactor.prompt.map { it?.title ?: "" }.distinctUntilChanged()
+ val title: Flow<String> =
+ promptSelectorInteractor.prompt.map { it?.title ?: "" }.distinctUntilChanged()
/** Subtitle for the prompt. */
- val subtitle: Flow<String> = interactor.prompt.map { it?.subtitle ?: "" }.distinctUntilChanged()
+ val subtitle: Flow<String> =
+ promptSelectorInteractor.prompt.map { it?.subtitle ?: "" }.distinctUntilChanged()
/** Description for the prompt. */
val description: Flow<String> =
- interactor.prompt.map { it?.description ?: "" }.distinctUntilChanged()
+ promptSelectorInteractor.prompt.map { it?.description ?: "" }.distinctUntilChanged()
/** If the indicator (help, error) message should be shown. */
val isIndicatorMessageVisible: Flow<Boolean> =
@@ -160,7 +171,9 @@ constructor(
/** If the icon can be used as a confirmation button. */
val isIconConfirmButton: Flow<Boolean> =
- combine(size, interactor.isConfirmationRequired) { size, isConfirmationRequired ->
+ combine(size, promptSelectorInteractor.isConfirmationRequired) {
+ size,
+ isConfirmationRequired ->
size.isNotSmall && isConfirmationRequired
}
@@ -169,7 +182,7 @@ constructor(
combine(
size,
isAuthenticated,
- interactor.isCredentialAllowed,
+ promptSelectorInteractor.isCredentialAllowed,
) { size, authState, credentialAllowed ->
size.isNotSmall && authState.isNotAuthenticated && !credentialAllowed
}
@@ -221,7 +234,7 @@ constructor(
combine(
size,
isAuthenticated,
- interactor.isCredentialAllowed,
+ promptSelectorInteractor.isCredentialAllowed,
) { size, authState, credentialAllowed ->
size.isNotSmall && authState.isNotAuthenticated && credentialAllowed
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
index b20e33a63776..83c239f169ef 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
@@ -44,12 +44,12 @@ constructor(
private var androidRestartRequested = false
override fun restartSystemUI(reason: String) {
- Log.d(FeatureFlagsDebug.TAG, "SystemUI Restart requested. Restarting when idle.")
+ Log.d(FeatureFlagsClassicDebug.TAG, "SystemUI Restart requested. Restarting when idle.")
scheduleRestart(reason)
}
override fun restartAndroid(reason: String) {
- Log.d(FeatureFlagsDebug.TAG, "Android Restart requested. Restarting when idle.")
+ Log.d(FeatureFlagsClassicDebug.TAG, "Android Restart requested. Restarting when idle.")
androidRestartRequested = true
scheduleRestart(reason)
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
index 95e7ad969e35..d48eb2927a14 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
@@ -23,6 +23,21 @@ import android.util.Dumpable
*
* See [Flags] for instructions on defining new flags.
*/
+interface FeatureFlagsClassic : FeatureFlags
+
+/**
+ * Class to manage simple DeviceConfig-based feature flags.
+ *
+ * See [Flags] for instructions on defining new flags.
+ */
+@Deprecated(
+ message = "Use FeatureFlagsClassic instead.",
+ replaceWith =
+ ReplaceWith(
+ "FeatureFlagsClassic",
+ "com.android.systemui.flags.FeatureFlagsClassic",
+ ),
+)
interface FeatureFlags : FlagListenable, Dumpable {
/** Returns a boolean value for the given flag. */
fun isEnabled(flag: UnreleasedFlag): Boolean
@@ -47,4 +62,4 @@ interface FeatureFlags : FlagListenable, Dumpable {
/** Returns an int value for a given flag/ */
fun getInt(flag: ResourceIntFlag): Int
-}
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
index 4c78e4ce4fe4..126a1b5e7115 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
@@ -67,7 +67,7 @@ import javax.inject.Named;
* To restore a flag back to its default, leave the `--ez value <0|1>` off of the command.
*/
@SysUISingleton
-public class FeatureFlagsDebug implements FeatureFlags {
+public class FeatureFlagsClassicDebug implements FeatureFlagsClassic {
static final String TAG = "SysUIFlags";
private final FlagManager mFlagManager;
@@ -116,7 +116,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
};
@Inject
- public FeatureFlagsDebug(
+ public FeatureFlagsClassicDebug(
FlagManager flagManager,
Context context,
GlobalSettings globalSettings,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicRelease.java
index e03b43873e05..79ebf9c7d8df 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicRelease.java
@@ -43,7 +43,7 @@ import javax.inject.Named;
* how to set flags.
*/
@SysUISingleton
-public class FeatureFlagsRelease implements FeatureFlags {
+public class FeatureFlagsClassicRelease implements FeatureFlagsClassic {
static final String TAG = "SysUIFlags";
private final Resources mResources;
@@ -89,7 +89,7 @@ public class FeatureFlagsRelease implements FeatureFlags {
};
@Inject
- public FeatureFlagsRelease(
+ public FeatureFlagsClassicRelease(
@Main Resources resources,
SystemPropertiesHelper systemProperties,
ServerFlagReader serverFlagReader,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
index 28c45b874b24..dd560b797c7e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
@@ -34,13 +34,13 @@ constructor(
dumpManager: DumpManager,
private val commandRegistry: CommandRegistry,
private val flagCommand: FlagCommand,
- private val featureFlags: FeatureFlagsDebug,
+ private val featureFlags: FeatureFlagsClassicDebug,
private val broadcastSender: BroadcastSender,
private val initializationChecker: InitializationChecker,
) : CoreStartable {
init {
- dumpManager.registerCriticalDumpable(FeatureFlagsDebug.TAG) { pw, args ->
+ dumpManager.registerCriticalDumpable(FeatureFlagsClassicDebug.TAG) { pw, args ->
featureFlags.dump(pw, args)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
index f97112d384be..dfcc7ead11d0 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
@@ -32,7 +32,7 @@ constructor(
) : CoreStartable {
init {
- dumpManager.registerCriticalDumpable(FeatureFlagsRelease.TAG) { pw, args ->
+ dumpManager.registerCriticalDumpable(FeatureFlagsClassicRelease.TAG) { pw, args ->
featureFlags.dump(pw, args)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
index bd0ed482c961..e3cc2b02177c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
@@ -38,12 +38,12 @@ public class FlagCommand implements Command {
private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
private final List<String> mSetCommands = List.of("set", "put");
- private final FeatureFlagsDebug mFeatureFlags;
+ private final FeatureFlagsClassicDebug mFeatureFlags;
private final Map<String, Flag<?>> mAllFlags;
@Inject
FlagCommand(
- FeatureFlagsDebug featureFlags,
+ FeatureFlagsClassicDebug featureFlags,
@Named(ALL_FLAGS) Map<String, Flag<?>> allFlags
) {
mFeatureFlags = featureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 2fc45740c133..90e78c608089 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -33,7 +33,7 @@ import com.android.systemui.flags.FlagsFactory.unreleasedFlag
* On public release builds, flags will always return their default value. There is no way to change
* their value on release builds.
*
- * See [FeatureFlagsDebug] for instructions on flipping the flags via adb.
+ * See [FeatureFlagsClassicDebug] for instructions on flipping the flags via adb.
*/
object Flags {
@JvmField val TEAMFOOD = unreleasedFlag("teamfood")
@@ -254,7 +254,7 @@ object Flags {
// TODO(b/290652751): Tracking bug.
@JvmField
val MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA =
- unreleasedFlag("migrate_split_keyguard_bottom_area")
+ unreleasedFlag("migrate_split_keyguard_bottom_area", teamfood = true)
/** Whether to listen for fingerprint authentication over keyguard occluding activities. */
// TODO(b/283260512): Tracking bug.
@@ -269,7 +269,7 @@ object Flags {
/** Migrate the lock icon view to the new keyguard root view. */
// TODO(b/286552209): Tracking bug.
- @JvmField val MIGRATE_LOCK_ICON = unreleasedFlag("migrate_lock_icon")
+ @JvmField val MIGRATE_LOCK_ICON = unreleasedFlag("migrate_lock_icon", teamfood = true)
// TODO(b/288276738): Tracking bug.
@JvmField val WIDGET_ON_KEYGUARD = unreleasedFlag("widget_on_keyguard")
@@ -355,7 +355,7 @@ object Flags {
// TODO(b/278068252): Tracking Bug
@JvmField
- val QS_PIPELINE_AUTO_ADD = unreleasedFlag("qs_pipeline_auto_add", teamfood = false)
+ val QS_PIPELINE_AUTO_ADD = unreleasedFlag("qs_pipeline_auto_add", teamfood = true)
// TODO(b/254512383): Tracking Bug
@JvmField
@@ -368,10 +368,6 @@ object Flags {
// TODO(b/244064524): Tracking Bug
@JvmField val QS_SECONDARY_DATA_SUB_INFO = releasedFlag("qs_secondary_data_sub_info")
- /** Enables Font Scaling Quick Settings tile */
- // TODO(b/269341316): Tracking Bug
- @JvmField val ENABLE_FONT_SCALING_TILE = releasedFlag("enable_font_scaling_tile")
-
/** Enables new QS Edit Mode visual refresh */
// TODO(b/269787742): Tracking Bug
@JvmField
@@ -398,6 +394,10 @@ object Flags {
// TODO(b/294588085): Tracking Bug
val WIFI_SECONDARY_NETWORKS = releasedFlag("wifi_secondary_networks")
+ // TODO(b/290676905): Tracking Bug
+ val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS =
+ unreleasedFlag("new_shade_carrier_group_mobile_icons")
+
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag("ongoing_call_status_bar_chip")
@@ -502,16 +502,6 @@ object Flags {
val WM_CAPTION_ON_SHELL =
sysPropBooleanFlag("persist.wm.debug.caption_on_shell", default = true)
- @Keep
- @JvmField
- val ENABLE_FLING_TO_DISMISS_BUBBLE =
- sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_bubble", default = true)
-
- @Keep
- @JvmField
- val ENABLE_FLING_TO_DISMISS_PIP =
- sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_pip", default = true)
-
// TODO(b/256873975): Tracking Bug
@JvmField
@Keep
@@ -533,13 +523,6 @@ object Flags {
teamfood = false
)
- // TODO(b/198643358): Tracking bug
- @Keep
- @JvmField
- val ENABLE_PIP_SIZE_LARGE_SCREEN =
- sysPropBooleanFlag("persist.wm.debug.enable_pip_size_large_screen", default = true)
-
-
// TODO(b/293252410) : Tracking Bug
@JvmField
val LOCKSCREEN_ENABLE_LANDSCAPE =
@@ -623,6 +606,10 @@ object Flags {
// TODO(b/251205791): Tracking Bug
@JvmField val SCREENSHOT_APP_CLIPS = releasedFlag("screenshot_app_clips")
+ /** TODO(b/295143676): Tracking bug. When enable, captures a screenshot for each display. */
+ @JvmField
+ val MULTI_DISPLAY_SCREENSHOT = unreleasedFlag("multi_display_screenshot")
+
// 1400 - columbus
// TODO(b/254512756): Tracking Bug
val QUICK_TAP_IN_PCC = releasedFlag("quick_tap_in_pcc")
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
index 3c5012559a89..d13fa1eb7628 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
@@ -25,6 +25,8 @@ import javax.inject.Named
interface FlagsCommonModule {
@Binds fun bindsRestarter(impl: ConditionalRestarter): Restarter
+ @Binds fun bindsClassic(impl: FeatureFlagsClassic): FeatureFlags
+
companion object {
const val ALL_FLAGS = "all_flags"
diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt
index 46e28a7d0ef2..9f41b61c6f4d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt
@@ -26,12 +26,12 @@ constructor(
private val barService: IStatusBarService,
) : Restarter {
override fun restartAndroid(reason: String) {
- Log.d(FeatureFlagsDebug.TAG, "Restarting Android: " + reason)
+ Log.d(FeatureFlagsClassicDebug.TAG, "Restarting Android: " + reason)
barService.restart()
}
override fun restartSystemUI(reason: String) {
- Log.d(FeatureFlagsDebug.TAG, "Restarting SystemUI: " + reason)
+ Log.d(FeatureFlagsClassicDebug.TAG, "Restarting SystemUI: " + reason)
System.exit(0)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 040ee7938f1d..3eb17400446c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -128,11 +128,11 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.EmergencyDialerConstants;
import com.android.systemui.util.RingerModeTracker;
@@ -141,7 +141,6 @@ import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -244,6 +243,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
private final IStatusBarService mStatusBarService;
protected final LightBarController mLightBarController;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final StatusBarWindowController mStatusBarWindowController;
private final IWindowManager mIWindowManager;
private final Executor mBackgroundExecutor;
private final RingerModeTracker mRingerModeTracker;
@@ -251,7 +251,6 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
protected Handler mMainHandler;
private int mSmallestScreenWidthDp;
private int mOrientation;
- private final Optional<CentralSurfaces> mCentralSurfacesOptional;
private final ShadeController mShadeController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -356,13 +355,13 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
IStatusBarService statusBarService,
LightBarController lightBarController,
NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarWindowController statusBarWindowController,
IWindowManager iWindowManager,
@Background Executor backgroundExecutor,
UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker,
@Main Handler handler,
PackageManager packageManager,
- Optional<CentralSurfaces> centralSurfacesOptional,
ShadeController shadeController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
DialogLaunchAnimator dialogLaunchAnimator) {
@@ -390,13 +389,13 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mStatusBarService = statusBarService;
mLightBarController = lightBarController;
mNotificationShadeWindowController = notificationShadeWindowController;
+ mStatusBarWindowController = statusBarWindowController;
mIWindowManager = iWindowManager;
mBackgroundExecutor = backgroundExecutor;
mRingerModeTracker = ringerModeTracker;
mMainHandler = handler;
mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
mOrientation = resources.getConfiguration().orientation;
- mCentralSurfacesOptional = centralSurfacesOptional;
mShadeController = shadeController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDialogLaunchAnimator = dialogLaunchAnimator;
@@ -449,10 +448,6 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
return mUiEventLogger;
}
- protected Optional<CentralSurfaces> getCentralSurfaces() {
- return mCentralSurfacesOptional;
- }
-
protected KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
return mKeyguardUpdateMonitor;
}
@@ -701,12 +696,21 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
protected ActionsDialogLite createDialog() {
initDialogItems();
- ActionsDialogLite dialog = new ActionsDialogLite(mContext,
+ ActionsDialogLite dialog = new ActionsDialogLite(
+ mContext,
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActionsLite,
- mAdapter, mOverflowAdapter, mSysuiColorExtractor, mStatusBarService,
+ mAdapter,
+ mOverflowAdapter,
+ mSysuiColorExtractor,
+ mStatusBarService,
mLightBarController,
- mNotificationShadeWindowController, this::onRefresh, mKeyguardShowing,
- mPowerAdapter, mUiEventLogger, mCentralSurfacesOptional,
+ mKeyguardStateController,
+ mNotificationShadeWindowController,
+ mStatusBarWindowController,
+ this::onRefresh,
+ mKeyguardShowing,
+ mPowerAdapter,
+ mUiEventLogger,
mShadeController,
mKeyguardUpdateMonitor,
mLockPatternUtils);
@@ -2208,13 +2212,14 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
private boolean mKeyguardShowing;
protected float mScrimAlpha;
protected final LightBarController mLightBarController;
+ private final KeyguardStateController mKeyguardStateController;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final StatusBarWindowController mStatusBarWindowController;
private ListPopupWindow mOverflowPopup;
private Dialog mPowerOptionsDialog;
protected final Runnable mOnRefreshCallback;
private UiEventLogger mUiEventLogger;
private GestureDetector mGestureDetector;
- private Optional<CentralSurfaces> mCentralSurfacesOptional;
private final ShadeController mShadeController;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private LockPatternUtils mLockPatternUtils;
@@ -2248,8 +2253,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
if (distanceY < 0 && distanceY > distanceX
- && e1.getY() <= mCentralSurfacesOptional.map(
- CentralSurfaces::getStatusBarHeight).orElse(0)) {
+ && e1.getY() <= mStatusBarWindowController.getStatusBarHeight()) {
// Downwards scroll from top
openShadeAndDismiss();
return true;
@@ -2261,8 +2265,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (velocityY > 0 && Math.abs(velocityY) > Math.abs(velocityX)
- && e1.getY() <= mCentralSurfacesOptional.map(
- CentralSurfaces::getStatusBarHeight).orElse(0)) {
+ && e1.getY() <= mStatusBarWindowController.getStatusBarHeight()) {
// Downwards fling from top
openShadeAndDismiss();
return true;
@@ -2281,14 +2284,20 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mOverriddenBackDispatcher = mockDispatcher;
}
- ActionsDialogLite(Context context, int themeRes, MyAdapter adapter,
+ ActionsDialogLite(Context context,
+ int themeRes,
+ MyAdapter adapter,
MyOverflowAdapter overflowAdapter,
- SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
+ SysuiColorExtractor sysuiColorExtractor,
+ IStatusBarService statusBarService,
LightBarController lightBarController,
+ KeyguardStateController keyguardStateController,
NotificationShadeWindowController notificationShadeWindowController,
- Runnable onRefreshCallback, boolean keyguardShowing,
- MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
- Optional<CentralSurfaces> centralSurfacesOptional,
+ StatusBarWindowController statusBarWindowController,
+ Runnable onRefreshCallback,
+ boolean keyguardShowing,
+ MyPowerOptionsAdapter powerAdapter,
+ UiEventLogger uiEventLogger,
ShadeController shadeController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
LockPatternUtils lockPatternUtils) {
@@ -2302,11 +2311,12 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
mLightBarController = lightBarController;
+ mKeyguardStateController = keyguardStateController;
mNotificationShadeWindowController = notificationShadeWindowController;
+ mStatusBarWindowController = statusBarWindowController;
mOnRefreshCallback = onRefreshCallback;
mKeyguardShowing = keyguardShowing;
mUiEventLogger = uiEventLogger;
- mCentralSurfacesOptional = centralSurfacesOptional;
mShadeController = shadeController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -2355,7 +2365,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
private void openShadeAndDismiss() {
mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
- if (mCentralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing).orElse(false)) {
+ if (mKeyguardStateController.isShowing()) {
// match existing lockscreen behavior to open QS when swiping from status bar
mShadeController.animateExpandQs();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
index 059f72b9f708..7234757081e2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
@@ -17,7 +17,10 @@
package com.android.systemui.keyguard.data.repository
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
+import androidx.core.view.children
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -96,8 +99,16 @@ constructor(
/** Determines the constraints for the ConstraintSet in the lockscreen root view. */
interface KeyguardBlueprint {
val id: String
+ val shouldRemoveUnconstrainedViews: Boolean
+ get() = true
- fun apply(constraintSet: ConstraintSet)
+ fun apply(constraintLayout: ConstraintSet)
+ fun removeUnConstrainedViews(constraintLayout: ConstraintLayout, constraintSet: ConstraintSet) {
+ constraintLayout.children
+ .map { it.id }
+ .filterNot { constraintSet.knownIds.contains(it) }
+ .forEach { constraintSet.setVisibility(it, View.GONE) }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index 635961b0ea01..e501ece626b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -54,7 +54,11 @@ constructor(
if (event.handleAction()) {
when (event.keyCode) {
KeyEvent.KEYCODE_MENU -> return dispatchMenuKeyEvent()
- KeyEvent.KEYCODE_SPACE -> return dispatchSpaceEvent()
+ KeyEvent.KEYCODE_SPACE,
+ KeyEvent.KEYCODE_ENTER ->
+ if (isDeviceInteractive()) {
+ return collapseShadeLockedOrShowPrimaryBouncer()
+ }
}
}
return false
@@ -90,16 +94,22 @@ constructor(
(statusBarStateController.state != StatusBarState.SHADE) &&
statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
if (shouldUnlockOnMenuPressed) {
- shadeController.animateCollapseShadeForced()
- return true
+ return collapseShadeLockedOrShowPrimaryBouncer()
}
return false
}
- private fun dispatchSpaceEvent(): Boolean {
- if (isDeviceInteractive() && statusBarStateController.state != StatusBarState.SHADE) {
- shadeController.animateCollapseShadeForced()
- return true
+ private fun collapseShadeLockedOrShowPrimaryBouncer(): Boolean {
+ when (statusBarStateController.state) {
+ StatusBarState.SHADE -> return false
+ StatusBarState.SHADE_LOCKED -> {
+ shadeController.animateCollapseShadeForced()
+ return true
+ }
+ StatusBarState.KEYGUARD -> {
+ statusBarKeyguardViewManager.showPrimaryBouncer(true)
+ return true
+ }
}
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index ed4dd6a15c18..e40c2793176e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -43,6 +43,7 @@ class KeyguardBlueprintViewBinder {
val emptyLayout = ConstraintSet.Layout()
knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
blueprint?.apply(this)
+ blueprint?.removeUnConstrainedViews(constraintLayout, this)
applyTo(constraintLayout)
}
Trace.endSection()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 5d028307a62d..34d6233deddb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -36,7 +36,6 @@ import android.provider.Settings;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.IWindowManager;
@@ -190,13 +189,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
if (updateIcon) {
mTile.setIcon(mDefaultIcon);
}
- // Update the label if there is no label or it is the default label.
- boolean updateLabel = mTile.getLabel() == null
- || TextUtils.equals(mTile.getLabel(), mDefaultLabel);
mDefaultLabel = info.loadLabel(pm);
- if (updateLabel) {
- mTile.setLabel(mDefaultLabel);
- }
+ mTile.setDefaultLabel(mDefaultLabel);
} catch (PackageManager.NameNotFoundException e) {
mDefaultIcon = null;
mDefaultLabel = null;
@@ -291,8 +285,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
if (tile.getIcon() != null || overwriteNulls) {
mTile.setIcon(tile.getIcon());
}
- if (tile.getLabel() != null || overwriteNulls) {
- mTile.setLabel(tile.getLabel());
+ if (tile.getCustomLabel() != null || overwriteNulls) {
+ mTile.setLabel(tile.getCustomLabel());
}
if (tile.getSubtitle() != null || overwriteNulls) {
mTile.setSubtitle(tile.getSubtitle());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt
index 021e632810f9..a321eef75a14 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt
@@ -113,7 +113,7 @@ internal fun writeToString(tile: Tile): String {
return with(tile) {
JSONObject()
.put(STATE, state)
- .put(LABEL, label)
+ .put(LABEL, customLabel)
.put(SUBTITLE, subtitle)
.put(CONTENT_DESCRIPTION, contentDescription)
.put(STATE_DESCRIPTION, stateDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 423fa80cacdb..1f9979a8b37c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -28,8 +28,6 @@ import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QSTile
@@ -64,7 +62,6 @@ constructor(
private val systemSettings: SystemSettings,
private val secureSettings: SecureSettings,
private val systemClock: SystemClock,
- private val featureFlags: FeatureFlags,
private val userTracker: UserTracker,
@Background private val backgroundDelayableExecutor: DelayableExecutor
) :
@@ -81,10 +78,6 @@ constructor(
) {
private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
- override fun isAvailable(): Boolean {
- return featureFlags.isEnabled(Flags.ENABLE_FONT_SCALING_TILE)
- }
-
override fun newTileState(): QSTile.State {
return QSTile.State()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 6e1ef9108256..c67078ff9093 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -128,12 +128,15 @@ public class InternetDialog extends SystemUIDialog implements
private TextView mMobileTitleText;
private TextView mMobileSummaryText;
private TextView mSecondaryMobileTitleText;
- private TextView mSecondaryMobileSummaryText;
+ private TextView mSecondaryMobileSummaryText;
private TextView mAirplaneModeSummaryText;
private Switch mMobileDataToggle;
private View mMobileToggleDivider;
private Switch mWiFiToggle;
private Button mDoneButton;
+
+ @VisibleForTesting
+ protected Button mShareWifiButton;
private Button mAirplaneModeButton;
private Drawable mBackgroundOn;
private KeyguardStateController mKeyguard;
@@ -142,7 +145,6 @@ public class InternetDialog extends SystemUIDialog implements
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private boolean mCanConfigMobileData;
private boolean mCanChangeWifiState;
-
// Wi-Fi entries
private int mWifiNetworkHeight;
@Nullable
@@ -236,6 +238,7 @@ public class InternetDialog extends SystemUIDialog implements
mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
mDoneButton = mDialogView.requireViewById(R.id.done_button);
+ mShareWifiButton = mDialogView.requireViewById(R.id.share_wifi_button);
mAirplaneModeButton = mDialogView.requireViewById(R.id.apm_button);
mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
@@ -274,6 +277,7 @@ public class InternetDialog extends SystemUIDialog implements
mConnectedWifListLayout.setVisibility(View.GONE);
mWifiRecyclerView.setVisibility(View.GONE);
mSeeAllLayout.setVisibility(View.GONE);
+ mShareWifiButton.setVisibility(View.GONE);
}
@Override
@@ -291,6 +295,7 @@ public class InternetDialog extends SystemUIDialog implements
mSeeAllLayout.setOnClickListener(null);
mWiFiToggle.setOnCheckedChangeListener(null);
mDoneButton.setOnClickListener(null);
+ mShareWifiButton.setOnClickListener(null);
mAirplaneModeButton.setOnClickListener(null);
mInternetDialogController.onStop();
mInternetDialogFactory.destroyDialog();
@@ -309,7 +314,7 @@ public class InternetDialog extends SystemUIDialog implements
* Update the internet dialog when receiving the callback.
*
* @param shouldUpdateMobileNetwork {@code true} for update the mobile network layout,
- * otherwise {@code false}.
+ * otherwise {@code false}.
*/
void updateDialog(boolean shouldUpdateMobileNetwork) {
if (DEBUG) {
@@ -366,6 +371,11 @@ public class InternetDialog extends SystemUIDialog implements
mInternetDialogController.setWifiEnabled(isChecked);
});
mDoneButton.setOnClickListener(v -> dismiss());
+ mShareWifiButton.setOnClickListener(v -> {
+ if (mInternetDialogController.mayLaunchShareWifiSettings(mConnectedWifiEntry)) {
+ mUiEventLogger.log(InternetDialogEvent.SHARE_WIFI_QS_BUTTON_CLICKED);
+ }
+ });
mAirplaneModeButton.setOnClickListener(v -> {
mInternetDialogController.setAirplaneModeDisabled();
});
@@ -526,6 +536,7 @@ public class InternetDialog extends SystemUIDialog implements
private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) {
if (!isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
mConnectedWifListLayout.setVisibility(View.GONE);
+ mShareWifiButton.setVisibility(View.GONE);
return;
}
mConnectedWifListLayout.setVisibility(View.VISIBLE);
@@ -535,6 +546,12 @@ public class InternetDialog extends SystemUIDialog implements
mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
mWifiSettingsIcon.setColorFilter(
mContext.getColor(R.color.connected_network_primary_color));
+ if (mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+ mConnectedWifiEntry) != null) {
+ mShareWifiButton.setVisibility(View.VISIBLE);
+ } else {
+ mShareWifiButton.setVisibility(View.GONE);
+ }
if (mSecondaryMobileNetworkLayout != null) {
mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
@@ -683,7 +700,8 @@ public class InternetDialog extends SystemUIDialog implements
mAlertDialog = new Builder(mContext)
.setTitle(R.string.mobile_data_disable_title)
.setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
- .setNegativeButton(android.R.string.cancel, (d, w) -> {})
+ .setNegativeButton(android.R.string.cancel, (d, w) -> {
+ })
.setPositiveButton(
com.android.internal.R.string.alert_windows_notification_turn_off_action,
(d, w) -> {
@@ -709,7 +727,8 @@ public class InternetDialog extends SystemUIDialog implements
.setTitle(mContext.getString(R.string.auto_data_switch_disable_title, carrierName))
.setMessage(R.string.auto_data_switch_disable_message)
.setNegativeButton(R.string.auto_data_switch_dialog_negative_button,
- (d, w) -> {})
+ (d, w) -> {
+ })
.setPositiveButton(R.string.auto_data_switch_dialog_positive_button,
(d, w) -> {
mInternetDialogController
@@ -815,7 +834,10 @@ public class InternetDialog extends SystemUIDialog implements
public enum InternetDialogEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "The Internet dialog became visible on the screen.")
- INTERNET_DIALOG_SHOW(843);
+ INTERNET_DIALOG_SHOW(843),
+
+ @UiEvent(doc = "The share wifi button is clicked.")
+ SHARE_WIFI_QS_BUTTON_CLICKED(1462);
private final int mId;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index ec1258049486..3c0b87d4a740 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -73,6 +73,7 @@ import com.android.settingslib.mobile.MobileMappings;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.settingslib.wifi.WifiUtils;
+import com.android.settingslib.wifi.dpp.WifiDppIntentHelper;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
@@ -1318,6 +1319,18 @@ public class InternetDialogController implements AccessPointController.AccessPoi
return mWifiIconInjector;
}
+ boolean mayLaunchShareWifiSettings(WifiEntry wifiEntry) {
+ Intent intent = getConfiguratorQrCodeGeneratorIntentOrNull(wifiEntry);
+ if (intent == null) {
+ return false;
+ }
+ if (mCallback != null) {
+ mCallback.dismissDialog();
+ }
+ mActivityStarter.startActivity(intent, false /* dismissShade */);
+ return true;
+ }
+
interface InternetDialogCallback {
void onRefreshCarrierInfo();
@@ -1403,4 +1416,17 @@ public class InternetDialogController implements AccessPointController.AccessPoi
}
}, SHORT_DURATION_TIMEOUT);
}
+
+ Intent getConfiguratorQrCodeGeneratorIntentOrNull(WifiEntry wifiEntry) {
+ if (!mFeatureFlags.isEnabled(Flags.SHARE_WIFI_QS_BUTTON) || wifiEntry == null
+ || mWifiManager == null || !wifiEntry.canShare()) {
+ return null;
+ }
+ Intent intent = new Intent();
+ intent.setAction(WifiDppIntentHelper.ACTION_CONFIGURATOR_AUTH_QR_CODE_GENERATOR);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ WifiDppIntentHelper.setConfiguratorIntentExtra(intent, mWifiManager,
+ wifiEntry.getWifiConfiguration());
+ return intent;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 7c4b0427f1ba..014093de62bd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -985,6 +985,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
// Make sure the clock is in the correct position after the unlock animation
// so that it's not in the wrong place when we show the keyguard again.
positionClockAndNotifications(true /* forceClockUpdate */);
+ mScrimController.onUnlockAnimationFinished();
}
private void unlockAnimationStarted(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 832a25bfbc41..798f2d586bab 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -21,8 +21,6 @@ import static com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.app.StatusBarManager;
-import android.media.AudioManager;
-import android.media.session.MediaSessionLegacyHelper;
import android.os.PowerManager;
import android.util.Log;
import android.view.GestureDetector;
@@ -47,6 +45,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.TransitionState;
@@ -101,13 +100,21 @@ public class NotificationShadeWindowViewController {
private final NotificationInsetsController mNotificationInsetsController;
private final boolean mIsTrackpadCommonEnabled;
private final FeatureFlags mFeatureFlags;
+ private final KeyEventInteractor mKeyEventInteractor;
private GestureDetector mPulsingWakeupGestureHandler;
private GestureDetector mDreamingWakeupGestureHandler;
private View mBrightnessMirror;
private boolean mTouchActive;
private boolean mTouchCancelled;
private MotionEvent mDownEvent;
+ // TODO rename to mLaunchAnimationRunning
private boolean mExpandAnimationRunning;
+ /**
+ * When mExpandAnimationRunning is true and the touch dispatcher receives a down even after
+ * uptime exceeds this, the dispatcher will stop blocking touches for the launch animation,
+ * which has presumabely not completed due to an error.
+ */
+ private long mLaunchAnimationTimeout;
private NotificationStackScrollLayout mStackScrollLayout;
private PhoneStatusBarViewController mStatusBarViewController;
private final CentralSurfaces mService;
@@ -164,7 +171,8 @@ public class NotificationShadeWindowViewController {
FeatureFlags featureFlags,
SystemClock clock,
BouncerMessageInteractor bouncerMessageInteractor,
- BouncerLogger bouncerLogger) {
+ BouncerLogger bouncerLogger,
+ KeyEventInteractor keyEventInteractor) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
mStatusBarStateController = statusBarStateController;
@@ -190,6 +198,7 @@ public class NotificationShadeWindowViewController {
mNotificationInsetsController = notificationInsetsController;
mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
mFeatureFlags = featureFlags;
+ mKeyEventInteractor = keyEventInteractor;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -278,7 +287,12 @@ public class NotificationShadeWindowViewController {
return logDownDispatch(ev, "touch cancelled", false);
}
if (mExpandAnimationRunning) {
- return logDownDispatch(ev, "expand animation running", false);
+ if (isDown && mClock.uptimeMillis() > mLaunchAnimationTimeout) {
+ mShadeLogger.d("NSWVC: launch animation timed out");
+ setExpandAnimationRunning(false);
+ } else {
+ return logDownDispatch(ev, "expand animation running", false);
+ }
}
if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
@@ -457,44 +471,17 @@ public class NotificationShadeWindowViewController {
@Override
public boolean interceptMediaKey(KeyEvent event) {
- return mService.interceptMediaKey(event);
+ return mKeyEventInteractor.interceptMediaKey(event);
}
@Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
- return mService.dispatchKeyEventPreIme(event);
+ return mKeyEventInteractor.dispatchKeyEventPreIme(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_BACK:
- if (!down) {
- mBackActionInteractor.onBackRequested();
- }
- return true;
- case KeyEvent.KEYCODE_MENU:
- if (!down) {
- return mService.onMenuPressed();
- }
- break;
- case KeyEvent.KEYCODE_SPACE:
- if (!down) {
- return mService.onSpacePressed();
- }
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_VOLUME_UP:
- if (mStatusBarStateController.isDozing()) {
- MediaSessionLegacyHelper.getHelper(mView.getContext())
- .sendVolumeKeyEvent(
- event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
- return true;
- }
- break;
- }
- return false;
+ return mKeyEventInteractor.dispatchKeyEvent(event);
}
});
@@ -555,8 +542,12 @@ public class NotificationShadeWindowViewController {
pw.println(mTouchActive);
}
- private void setExpandAnimationRunning(boolean running) {
+ @VisibleForTesting
+ void setExpandAnimationRunning(boolean running) {
if (mExpandAnimationRunning != running) {
+ if (running) {
+ mLaunchAnimationTimeout = mClock.uptimeMillis() + 5000;
+ }
mExpandAnimationRunning = running;
mNotificationShadeWindowController.setLaunchingActivity(mExpandAnimationRunning);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
index 8586828af0cd..8612cdf12c6e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
@@ -34,6 +34,7 @@ import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView;
import com.android.systemui.util.LargeScreenUtils;
import java.util.Objects;
@@ -44,6 +45,7 @@ public class ShadeCarrier extends LinearLayout {
private TextView mCarrierText;
private ImageView mMobileSignal;
private ImageView mMobileRoaming;
+ private ModernShadeCarrierGroupMobileView mModernMobileView;
private View mSpacer;
@Nullable
private CellSignalState mLastSignalState;
@@ -77,6 +79,23 @@ public class ShadeCarrier extends LinearLayout {
updateResources();
}
+ /** Removes a ModernStatusBarMobileView from the ViewGroup. */
+ public void removeModernMobileView() {
+ if (mModernMobileView != null) {
+ removeView(mModernMobileView);
+ mModernMobileView = null;
+ }
+ }
+
+ /** Adds a ModernStatusBarMobileView to the ViewGroup. */
+ public void addModernMobileView(ModernShadeCarrierGroupMobileView mobileView) {
+ mModernMobileView = mobileView;
+ mMobileGroup.setVisibility(View.GONE);
+ mSpacer.setVisibility(View.GONE);
+ mCarrierText.setVisibility(View.GONE);
+ addView(mobileView);
+ }
+
/**
* Update the state of this view
* @param state the current state of the signal for this view
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
index ad49b267c6ac..98d8a53b83c8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
@@ -16,6 +16,7 @@
package com.android.systemui.shade.carrier;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import android.annotation.MainThread;
@@ -46,8 +47,17 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
import com.android.systemui.util.CarrierConfigTracker;
+import java.util.List;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -62,12 +72,16 @@ public class ShadeCarrierGroupController {
private final ActivityStarter mActivityStarter;
private final Handler mBgHandler;
+ private final Context mContext;
private final NetworkController mNetworkController;
private final CarrierTextManager mCarrierTextManager;
private final TextView mNoSimTextView;
// Non final for testing
private H mMainHandler;
private final Callback mCallback;
+ private final MobileIconsViewModel mMobileIconsViewModel;
+ private final MobileContextProvider mMobileContextProvider;
+ private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private boolean mListening;
private final CellSignalState[] mInfos =
new CellSignalState[SIM_SLOTS];
@@ -91,7 +105,7 @@ public class ShadeCarrierGroupController {
Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
return;
}
- if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ if (slotIndex == INVALID_SIM_SLOT_INDEX) {
Log.e(TAG, "Invalid SIM slot index for subscription: " + indicators.subId);
return;
}
@@ -129,15 +143,25 @@ public class ShadeCarrierGroupController {
}
}
- private ShadeCarrierGroupController(ShadeCarrierGroup view, ActivityStarter activityStarter,
- @Background Handler bgHandler, @Main Looper mainLooper,
+ private ShadeCarrierGroupController(
+ ShadeCarrierGroup view,
+ ActivityStarter activityStarter,
+ @Background Handler bgHandler,
+ @Main Looper mainLooper,
NetworkController networkController,
- CarrierTextManager.Builder carrierTextManagerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
-
+ CarrierTextManager.Builder carrierTextManagerBuilder,
+ Context context,
+ CarrierConfigTracker carrierConfigTracker,
+ SlotIndexResolver slotIndexResolver,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider,
+ StatusBarPipelineFlags statusBarPipelineFlags
+ ) {
+ mContext = context;
mActivityStarter = activityStarter;
mBgHandler = bgHandler;
mNetworkController = networkController;
+ mStatusBarPipelineFlags = statusBarPipelineFlags;
mCarrierTextManager = carrierTextManagerBuilder
.setShowAirplaneMode(false)
.setShowMissingSim(false)
@@ -162,6 +186,14 @@ public class ShadeCarrierGroupController {
mCarrierGroups[1] = view.getCarrier2View();
mCarrierGroups[2] = view.getCarrier3View();
+ mMobileContextProvider = mobileContextProvider;
+ mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
+
+ if (mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+ mobileUiAdapter.setShadeCarrierGroupController(this);
+ MobileIconsBinder.bind(view, mMobileIconsViewModel);
+ }
+
mCarrierDividers[0] = view.getCarrierDivider1();
mCarrierDividers[1] = view.getCarrierDivider2();
@@ -193,6 +225,50 @@ public class ShadeCarrierGroupController {
});
}
+ /** Updates the number of visible mobile icons using the new pipeline. */
+ public void updateModernMobileIcons(List<Integer> subIds) {
+ if (!mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+ Log.d(TAG, "ignoring new pipeline callback because new mobile icon is disabled");
+ return;
+ }
+
+ for (ShadeCarrier carrier : mCarrierGroups) {
+ carrier.removeModernMobileView();
+ }
+
+ List<IconData> iconDataList = processSubIdList(subIds);
+
+ for (IconData iconData : iconDataList) {
+ ShadeCarrier carrier = mCarrierGroups[iconData.slotIndex];
+
+ Context mobileContext =
+ mMobileContextProvider.getMobileContextForSub(iconData.subId, mContext);
+ ModernShadeCarrierGroupMobileView modernMobileView = ModernShadeCarrierGroupMobileView
+ .constructAndBind(
+ mobileContext,
+ mMobileIconsViewModel.getLogger(),
+ "mobile_carrier_shade_group",
+ (ShadeCarrierGroupMobileIconViewModel) mMobileIconsViewModel
+ .viewModelForSub(iconData.subId,
+ StatusBarLocation.SHADE_CARRIER_GROUP)
+ );
+ carrier.addModernMobileView(modernMobileView);
+ }
+ }
+
+ @VisibleForTesting
+ List<IconData> processSubIdList(List<Integer> subIds) {
+ return subIds
+ .stream()
+ .limit(SIM_SLOTS)
+ .map(subId -> new IconData(subId, getSlotIndex(subId)))
+ .filter(iconData ->
+ iconData.slotIndex < SIM_SLOTS
+ && iconData.slotIndex != INVALID_SIM_SLOT_INDEX
+ )
+ .toList();
+ }
+
@VisibleForTesting
protected int getSlotIndex(int subscriptionId) {
return mSlotIndexResolver.getSlotIndex(subscriptionId);
@@ -269,8 +345,12 @@ public class ShadeCarrierGroupController {
}
}
- for (int i = 0; i < SIM_SLOTS; i++) {
- mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
+ if (mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+ Log.d(TAG, "ignoring old pipeline callback because new mobile icon is enabled");
+ } else {
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
+ }
}
mCarrierDividers[0].setVisibility(
@@ -306,7 +386,7 @@ public class ShadeCarrierGroupController {
Log.w(TAG, "updateInfoCarrier - slot: " + slot);
continue;
}
- if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ if (slot == INVALID_SIM_SLOT_INDEX) {
Log.e(TAG,
"Invalid SIM slot index for subscription: "
+ info.subscriptionIds[i]);
@@ -385,12 +465,24 @@ public class ShadeCarrierGroupController {
private final Context mContext;
private final CarrierConfigTracker mCarrierConfigTracker;
private final SlotIndexResolver mSlotIndexResolver;
+ private final MobileUiAdapter mMobileUiAdapter;
+ private final MobileContextProvider mMobileContextProvider;
+ private final StatusBarPipelineFlags mStatusBarPipelineFlags;
@Inject
- public Builder(ActivityStarter activityStarter, @Background Handler handler,
- @Main Looper looper, NetworkController networkController,
- CarrierTextManager.Builder carrierTextControllerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
+ public Builder(
+ ActivityStarter activityStarter,
+ @Background Handler handler,
+ @Main Looper looper,
+ NetworkController networkController,
+ CarrierTextManager.Builder carrierTextControllerBuilder,
+ Context context,
+ CarrierConfigTracker carrierConfigTracker,
+ SlotIndexResolver slotIndexResolver,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider,
+ StatusBarPipelineFlags statusBarPipelineFlags
+ ) {
mActivityStarter = activityStarter;
mHandler = handler;
mLooper = looper;
@@ -399,6 +491,9 @@ public class ShadeCarrierGroupController {
mContext = context;
mCarrierConfigTracker = carrierConfigTracker;
mSlotIndexResolver = slotIndexResolver;
+ mMobileUiAdapter = mobileUiAdapter;
+ mMobileContextProvider = mobileContextProvider;
+ mStatusBarPipelineFlags = statusBarPipelineFlags;
}
public Builder setShadeCarrierGroup(ShadeCarrierGroup view) {
@@ -407,9 +502,20 @@ public class ShadeCarrierGroupController {
}
public ShadeCarrierGroupController build() {
- return new ShadeCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
- mNetworkController, mCarrierTextControllerBuilder, mContext,
- mCarrierConfigTracker, mSlotIndexResolver);
+ return new ShadeCarrierGroupController(
+ mView,
+ mActivityStarter,
+ mHandler,
+ mLooper,
+ mNetworkController,
+ mCarrierTextControllerBuilder,
+ mContext,
+ mCarrierConfigTracker,
+ mSlotIndexResolver,
+ mMobileUiAdapter,
+ mMobileContextProvider,
+ mStatusBarPipelineFlags
+ );
}
}
@@ -448,4 +554,15 @@ public class ShadeCarrierGroupController {
return SubscriptionManager.getSlotIndex(subscriptionId);
}
}
+
+ @VisibleForTesting
+ static class IconData {
+ public final int subId;
+ public final int slotIndex;
+
+ IconData(int subId, int slotIndex) {
+ this.subId = subId;
+ this.slotIndex = slotIndex;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 634611122184..d667b91ea5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -388,7 +388,10 @@ constructor(
})
ssView.setFalsingManager(falsingManager)
ssView.setKeyguardBypassEnabled(bypassController.bypassEnabled)
- return (ssView as View).apply { addOnAttachStateChangeListener(stateChangeListener) }
+ return (ssView as View).apply {
+ setTag(R.id.tag_smartspace_view, Any())
+ addOnAttachStateChangeListener(stateChangeListener)
+ }
}
private fun connectSession() {
@@ -451,12 +454,6 @@ constructor(
session?.requestSmartspaceUpdate()
}
- fun removeViewsFromParent(viewGroup: ViewGroup) {
- smartspaceViews.toList().forEach {
- viewGroup.removeView(it as View)
- }
- }
-
/**
* Disconnects the smartspace view from the smartspace service and cleans up any resources.
*/
@@ -597,3 +594,4 @@ constructor(
}
}
}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt
index b0023305ecdd..c27682726da5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt
@@ -20,7 +20,9 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.TextView
+import com.android.internal.widget.ConversationLayout
import com.android.internal.widget.ImageFloatingTextView
+import com.android.internal.widget.MessagingLayout
import javax.inject.Inject
class PrecomputedTextViewFactory @Inject constructor() : NotifRemoteViewsFactory {
@@ -35,6 +37,10 @@ class PrecomputedTextViewFactory @Inject constructor() : NotifRemoteViewsFactory
TextView::class.java.simpleName -> PrecomputedTextView(context, attrs)
ImageFloatingTextView::class.java.name ->
PrecomputedImageFloatingTextView(context, attrs)
+ MessagingLayout::class.java.name ->
+ MessagingLayout(context, attrs).apply { setPrecomputedTextEnabled(true) }
+ ConversationLayout::class.java.name ->
+ ConversationLayout(context, attrs).apply { setPrecomputedTextEnabled(true) }
else -> null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 5c28be3bc678..d0a093cf905a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -25,7 +25,6 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RemoteAnimationAdapter;
import android.view.View;
@@ -197,8 +196,6 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner {
/** Get the Keyguard Message Area that displays auth messages. */
AuthKeyguardMessageArea getKeyguardMessageArea();
- int getStatusBarHeight();
-
boolean isLaunchingActivityOverLockscreen();
void onKeyguardViewManagerStatesUpdated();
@@ -229,9 +226,6 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner {
/** */
boolean getCommandQueuePanelsEnabled();
- /** */
- int getStatusBarWindowState();
-
BiometricUnlockController getBiometricUnlockController();
void showWirelessChargingAnimation(int batteryLevel);
@@ -276,19 +270,11 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner {
void userActivity();
- boolean interceptMediaKey(KeyEvent event);
-
- boolean dispatchKeyEventPreIme(KeyEvent event);
-
- boolean onMenuPressed();
-
void endAffordanceLaunch();
/** Should the keyguard be hidden immediately in response to a back press/gesture. */
boolean shouldKeyguardHideImmediately();
- boolean onSpacePressed();
-
void showBouncerWithDimissAndCancelIfKeyguard(OnDismissAction performAction,
Runnable cancelAction);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 8ffd43a6eb89..a1776c667b94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -89,7 +89,6 @@ import android.util.MathUtils;
import android.view.Display;
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ThreadedRenderer;
import android.view.View;
@@ -1689,11 +1688,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
return getNotificationShadeWindowViewController().getKeyguardMessageArea();
}
- @Override
- public int getStatusBarHeight() {
- return mStatusBarWindowController.getStatusBarHeight();
- }
-
private void updateReportRejectedTouchVisibility() {
if (mReportRejectedTouch == null) {
return;
@@ -1819,11 +1813,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
}
@Override
- public int getStatusBarWindowState() {
- return mStatusBarWindowState;
- }
-
- @Override
public BiometricUnlockController getBiometricUnlockController() {
return mBiometricUnlockController;
}
@@ -2636,44 +2625,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
}
@Override
- public boolean interceptMediaKey(KeyEvent event) {
- return mState == StatusBarState.KEYGUARD
- && mStatusBarKeyguardViewManager.interceptMediaKey(event);
- }
-
- /**
- * While IME is active and a BACK event is detected, check with
- * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event
- * should be handled before routing to IME, in order to prevent the user having to hit back
- * twice to exit bouncer.
- */
- @Override
- public boolean dispatchKeyEventPreIme(KeyEvent event) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_BACK:
- if (mState == StatusBarState.KEYGUARD
- && mStatusBarKeyguardViewManager.dispatchBackKeyEventPreIme()) {
- return mBackActionInteractor.onBackRequested();
- }
- }
- return false;
- }
-
- protected boolean shouldUnlockOnMenuPressed() {
- return mDeviceInteractive && mState != StatusBarState.SHADE
- && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed();
- }
-
- @Override
- public boolean onMenuPressed() {
- if (shouldUnlockOnMenuPressed()) {
- mShadeController.animateCollapseShadeForced();
- return true;
- }
- return false;
- }
-
- @Override
public void endAffordanceLaunch() {
releaseGestureWakeLock();
mCameraLauncherLazy.get().setLaunchingAffordance(false);
@@ -2692,15 +2643,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
return (isScrimmedBouncer || isBouncerOverDream);
}
- @Override
- public boolean onSpacePressed() {
- if (mDeviceInteractive && mState != StatusBarState.SHADE) {
- mShadeController.animateCollapseShadeForced();
- return true;
- }
- return false;
- }
-
private void showBouncerOrLockScreenIfKeyguard() {
// If the keyguard is animating away, we aren't really the keyguard anymore and should not
// show the bouncer/lockscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 4de669c0b34a..cc41bf843565 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -15,7 +15,6 @@
*/
package com.android.systemui.statusbar.phone
-import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATUS_BAR
import android.content.res.Configuration
import android.graphics.Point
@@ -34,6 +33,7 @@ import com.android.systemui.shade.ShadeLogger
import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UNFOLD_STATUS_BAR
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
@@ -53,6 +53,7 @@ class PhoneStatusBarViewController private constructor(
view: PhoneStatusBarView,
@Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
private val centralSurfaces: CentralSurfaces,
+ private val statusBarWindowStateController: StatusBarWindowStateController,
private val shadeController: ShadeController,
private val shadeViewController: ShadeViewController,
private val windowRootView: Provider<WindowRootView>,
@@ -148,7 +149,7 @@ class PhoneStatusBarViewController private constructor(
/** Called when a touch event occurred on {@link PhoneStatusBarView}. */
fun onTouch(event: MotionEvent) {
- if (centralSurfaces.statusBarWindowState == WINDOW_STATE_SHOWING) {
+ if (statusBarWindowStateController.windowIsShowing()) {
val upOrCancel =
event.action == MotionEvent.ACTION_UP ||
event.action == MotionEvent.ACTION_CANCEL
@@ -242,6 +243,7 @@ class PhoneStatusBarViewController private constructor(
private val featureFlags: FeatureFlags,
private val userChipViewModel: StatusBarUserChipViewModel,
private val centralSurfaces: CentralSurfaces,
+ private val statusBarWindowStateController: StatusBarWindowStateController,
private val shadeController: ShadeController,
private val shadeViewController: ShadeViewController,
private val windowRootView: Provider<WindowRootView>,
@@ -264,6 +266,7 @@ class PhoneStatusBarViewController private constructor(
view,
progressProvider.getOrNull(),
centralSurfaces,
+ statusBarWindowStateController,
shadeController,
shadeViewController,
windowRootView,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index fc661384146c..62a8cfde80da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -709,6 +709,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
}
+ public void onUnlockAnimationFinished() {
+ mAnimatingPanelExpansionOnUnlock = false;
+ applyAndDispatchState();
+ }
+
/**
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
index 5ace22695ec3..32e5c355889a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
@@ -24,4 +24,6 @@ enum class StatusBarLocation {
KEYGUARD,
/** Quick settings (inside the shade). */
QS,
+ /** ShadeCarrierGroup (above QS status bar in expanded mode). */
+ SHADE_CARRIER_GROUP,
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
index 6e51ed0eba37..c69577308608 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
@@ -18,6 +18,9 @@ package com.android.systemui.statusbar.pipeline
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.shade.carrier.ShadeCarrierGroup
import javax.inject.Inject
/** All flagging methods related to the new status bar pipeline (see b/238425913). */
@@ -26,11 +29,19 @@ class StatusBarPipelineFlags
@Inject
constructor(
context: Context,
+ private val featureFlags: FeatureFlags,
) {
private val mobileSlot = context.getString(com.android.internal.R.string.status_bar_mobile)
private val wifiSlot = context.getString(com.android.internal.R.string.status_bar_wifi)
/**
+ * True if we should display the mobile icons in the [ShadeCarrierGroup] using the new status
+ * bar Data pipeline.
+ */
+ fun useNewShadeCarrierGroupMobileIcons(): Boolean =
+ featureFlags.isEnabled(Flags.NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS)
+
+ /**
* For convenience in the StatusBarIconController, we want to gate some actions based on slot
* name and the flag together.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
index 78231e28803e..99ed2d99c749 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
@@ -60,6 +60,19 @@ sealed interface NetworkNameModel : Diffable<NetworkNameModel> {
}
}
+ /** This name has been derived from SubscriptionModel. see [SubscriptionModel] */
+ data class SubscriptionDerived(override val name: String) : NetworkNameModel {
+ override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
+ if (prevVal !is SubscriptionDerived || prevVal.name != name) {
+ row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
+ }
+ }
+
+ override fun logFull(row: TableRowLogger) {
+ row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
+ }
+ }
+
/**
* This name has been derived from the sim via
* [android.telephony.TelephonyManager.getSimOperatorName].
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index 16c4027ef645..27f6df4c26e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -34,4 +34,7 @@ data class SubscriptionModel(
/** Subscriptions in the same group may be filtered or treated as a single subscription */
val groupUuid: ParcelUuid? = null,
+
+ /** Text representing the name for this connection */
+ val carrierName: String,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index c1af6df12bd1..a89b1b2db6b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -115,10 +115,18 @@ interface MobileConnectionRepository {
*/
val cdmaRoaming: StateFlow<Boolean>
- /** The service provider name for this network connection, or the default name */
+ /** The service provider name for this network connection, or the default name. */
val networkName: StateFlow<NetworkNameModel>
/**
+ * The service provider name for this network connection, or the default name.
+ *
+ * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+ * provided is identical
+ */
+ val carrierName: StateFlow<NetworkNameModel>
+
+ /**
* True if this type of connection is allowed while airplane mode is on, and false otherwise.
*/
val isAllowedDuringAirplaneMode: StateFlow<Boolean>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
index 17d20c297861..c576b822da15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -184,7 +184,10 @@ class DemoMobileConnectionRepository(
override val cdmaRoaming = MutableStateFlow(false)
- override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
+ override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived(DEMO_CARRIER_NAME))
+
+ override val carrierName =
+ MutableStateFlow(NetworkNameModel.SubscriptionDerived(DEMO_CARRIER_NAME))
override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
@@ -200,6 +203,7 @@ class DemoMobileConnectionRepository(
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(event.name)
+ carrierName.value = NetworkNameModel.SubscriptionDerived("${event.name} ${event.subId}")
_carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID
@@ -227,6 +231,7 @@ class DemoMobileConnectionRepository(
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
+ carrierName.value = NetworkNameModel.SubscriptionDerived(CARRIER_MERGED_NAME)
// TODO(b/276943904): is carrierId a thing with carrier merged networks?
_carrierId.value = INVALID_SUBSCRIPTION_ID
numberOfLevels.value = event.numberOfLevels
@@ -248,6 +253,7 @@ class DemoMobileConnectionRepository(
}
companion object {
+ private const val DEMO_CARRIER_NAME = "Demo Carrier"
private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 0e4ceebcc854..ee13d93e735d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -92,9 +92,12 @@ constructor(
private fun maybeCreateSubscription(subId: Int) {
if (!subscriptionInfoCache.containsKey(subId)) {
- SubscriptionModel(subscriptionId = subId, isOpportunistic = false).also {
- subscriptionInfoCache[subId] = it
- }
+ SubscriptionModel(
+ subscriptionId = subId,
+ isOpportunistic = false,
+ carrierName = DEFAULT_CARRIER_NAME,
+ )
+ .also { subscriptionInfoCache[subId] = it }
_subscriptions.value = subscriptionInfoCache.values.toList()
}
@@ -327,6 +330,7 @@ constructor(
private const val TAG = "DemoMobileConnectionsRepo"
private const val DEFAULT_SUB_ID = 1
+ private const val DEFAULT_CARRIER_NAME = "demo carrier"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
index 65f486683837..28be3be28928 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
@@ -108,6 +108,8 @@ class CarrierMergedConnectionRepository(
NetworkNameModel.SimDerived(telephonyManager.simOperatorName),
)
+ override val carrierName: StateFlow<NetworkNameModel> = networkName
+
override val numberOfLevels: StateFlow<Int> =
wifiRepository.wifiNetwork
.map {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index 8ba7d2197c14..ee11c06ef3f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -22,6 +22,7 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -47,6 +48,7 @@ class FullMobileConnectionRepository(
override val subId: Int,
startingIsCarrierMerged: Boolean,
override val tableLogBuffer: TableLogBuffer,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
private val defaultNetworkName: NetworkNameModel,
private val networkNameSeparator: String,
@Application scope: CoroutineScope,
@@ -80,6 +82,7 @@ class FullMobileConnectionRepository(
mobileRepoFactory.build(
subId,
tableLogBuffer,
+ subscriptionModel,
defaultNetworkName,
networkNameSeparator,
)
@@ -287,6 +290,16 @@ class FullMobileConnectionRepository(
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
+ override val carrierName =
+ activeRepo
+ .flatMapLatest { it.carrierName }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ initialValue = activeRepo.value.carrierName.value,
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierName.value)
+
override val isAllowedDuringAirplaneMode =
activeRepo
.flatMapLatest { it.isAllowedDuringAirplaneMode }
@@ -307,6 +320,7 @@ class FullMobileConnectionRepository(
fun build(
subId: Int,
startingIsCarrierMerged: Boolean,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
): FullMobileConnectionRepository {
@@ -317,6 +331,7 @@ class FullMobileConnectionRepository(
subId,
startingIsCarrierMerged,
mobileLogger,
+ subscriptionModel,
defaultNetworkName,
networkNameSeparator,
scope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index aadc975a10de..1f1ac92b3956 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
@@ -80,6 +81,7 @@ import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
class MobileConnectionRepositoryImpl(
override val subId: Int,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
private val telephonyManager: TelephonyManager,
@@ -281,6 +283,14 @@ class MobileConnectionRepositoryImpl(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
+ override val carrierName =
+ subscriptionModel
+ .map {
+ it?.let { model -> NetworkNameModel.SubscriptionDerived(model.carrierName) }
+ ?: defaultNetworkName
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
+
/**
* There are a few cases where we will need to poll [TelephonyManager] so we can update some
* internal state where callbacks aren't provided. Any of those events should be merged into
@@ -350,11 +360,13 @@ class MobileConnectionRepositoryImpl(
fun build(
subId: Int,
mobileLogger: TableLogBuffer,
+ subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
): MobileConnectionRepository {
return MobileConnectionRepositoryImpl(
subId,
+ subscriptionModel,
defaultNetworkName,
networkNameSeparator,
telephonyManager.createForSubscriptionId(subId),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 54948a4a41c8..67b04db64463 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -319,10 +319,17 @@ constructor(
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
+ private fun subscriptionModelForSubId(subId: Int): StateFlow<SubscriptionModel?> {
+ return subscriptions
+ .map { list -> list.firstOrNull { model -> model.subscriptionId == subId } }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+ }
+
private fun createRepositoryForSubId(subId: Int): FullMobileConnectionRepository {
return fullMobileRepoFactory.build(
subId,
isCarrierMerged(subId),
+ subscriptionModelForSubId(subId),
defaultNetworkName,
networkNameSeparator,
)
@@ -373,6 +380,7 @@ constructor(
subscriptionId = subscriptionId,
isOpportunistic = isOpportunistic,
groupUuid = groupUuid,
+ carrierName = carrierName.toString(),
)
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 1a138272d67c..4cfde5bd5622 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -92,6 +92,22 @@ interface MobileIconInteractor {
*/
val networkName: StateFlow<NetworkNameModel>
+ /**
+ * Provider name for this network connection. The name can be one of 3 values:
+ * 1. The default network name, if one is configured
+ * 2. A name provided by the [SubscriptionModel] of this network connection
+ * 3. Or, in the case where the repository sends us the default network name, we check for an
+ * override in [connectionInfo.operatorAlphaShort], a value that is derived from
+ * [ServiceState]
+ *
+ * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+ * provided is identical
+ */
+ val carrierName: StateFlow<String>
+
+ /** True if there is only one active subscription. */
+ val isSingleCarrier: StateFlow<Boolean>
+
/** True if this line of service is emergency-only */
val isEmergencyOnly: StateFlow<Boolean>
@@ -126,6 +142,7 @@ class MobileIconInteractorImpl(
defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
override val alwaysShowDataRatIcon: StateFlow<Boolean>,
override val alwaysUseCdmaLevel: StateFlow<Boolean>,
+ override val isSingleCarrier: StateFlow<Boolean>,
override val mobileIsDefault: StateFlow<Boolean>,
defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
@@ -171,6 +188,22 @@ class MobileIconInteractorImpl(
connectionRepository.networkName.value
)
+ override val carrierName =
+ combine(connectionRepository.operatorAlphaShort, connectionRepository.carrierName) {
+ operatorAlphaShort,
+ networkName ->
+ if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+ operatorAlphaShort
+ } else {
+ networkName.name
+ }
+ }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ connectionRepository.carrierName.value.name
+ )
+
/** What the mobile icon would be before carrierId overrides */
private val defaultNetworkType: StateFlow<MobileIconGroup> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index e90f40c74cc5..d08808b65399 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -76,6 +76,9 @@ interface MobileIconsInteractor {
/** True if the CDMA level should be preferred over the primary level. */
val alwaysUseCdmaLevel: StateFlow<Boolean>
+ /** True if there is only one active subscription. */
+ val isSingleCarrier: StateFlow<Boolean>
+
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
@@ -252,6 +255,17 @@ constructor(
.mapLatest { it.alwaysShowCdmaRssi }
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ override val isSingleCarrier: StateFlow<Boolean> =
+ mobileConnectionsRepo.subscriptions
+ .map { it.size == 1 }
+ .logDiffsForTable(
+ tableLogger,
+ columnPrefix = LOGGING_PREFIX,
+ columnName = "isSingleCarrier",
+ initialValue = false,
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
/** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
mobileConnectionsRepo.defaultMobileIconGroup.stateIn(
@@ -298,6 +312,7 @@ constructor(
activeDataConnectionHasDataEnabled,
alwaysShowDataRatIcon,
alwaysUseCdmaLevel,
+ isSingleCarrier,
mobileIsDefault,
defaultMobileIconMapping,
defaultMobileIconGroup,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index d7fcf4876c28..02e50a007f50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.shade.carrier.ShadeCarrierGroupController
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
@@ -49,6 +50,8 @@ constructor(
private var isCollecting: Boolean = false
private var lastValue: List<Int>? = null
+ private var shadeCarrierGroupController: ShadeCarrierGroupController? = null
+
override fun start() {
// Start notifying the icon controller of subscriptions
scope.launch {
@@ -57,10 +60,16 @@ constructor(
logger.logUiAdapterSubIdsSentToIconController(it)
lastValue = it
iconController.setNewMobileIconSubIds(it)
+ shadeCarrierGroupController?.updateModernMobileIcons(it)
}
}
}
+ /** Set the [ShadeCarrierGroupController] to notify of subscription updates */
+ fun setShadeCarrierGroupController(controller: ShadeCarrierGroupController) {
+ shadeCarrierGroupController = controller
+ }
+
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.println("isCollecting=$isCollecting")
pw.println("Last values sent to icon controller: $lastValue")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
index cea6654a48de..2af6795b39c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -57,7 +57,7 @@ constructor(
{
str1 = view.getIdForLogging()
str2 = viewModel.getIdForLogging()
- str3 = viewModel.locationName
+ str3 = viewModel.location.name
},
{ "New view binding. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
)
@@ -71,7 +71,7 @@ constructor(
{
str1 = view.getIdForLogging()
str2 = viewModel.getIdForLogging()
- str3 = viewModel.locationName
+ str3 = viewModel.location.name
},
{ "Collection started. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
)
@@ -85,7 +85,7 @@ constructor(
{
str1 = view.getIdForLogging()
str2 = viewModel.getIdForLogging()
- str3 = viewModel.locationName
+ str3 = viewModel.location.name
},
{ "Collection stopped. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index 55bc8d58be23..4b2fb4373957 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -50,6 +50,7 @@ object MobileIconBinder {
fun bind(
view: ViewGroup,
viewModel: LocationBasedMobileViewModel,
+ @StatusBarIconView.VisibleState initialVisibilityState: Int = STATE_HIDDEN,
logger: MobileViewLogger,
): ModernStatusBarViewBinding {
val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group)
@@ -68,12 +69,12 @@ object MobileIconBinder {
// TODO(b/238425913): We should log this visibility state.
@StatusBarIconView.VisibleState
- val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
+ val visibilityState: MutableStateFlow<Int> = MutableStateFlow(initialVisibilityState)
val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
- var isCollecting: Boolean = false
+ var isCollecting = false
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt
new file mode 100644
index 000000000000..081e1015e26e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.binder
+
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.util.AutoMarqueeTextView
+import kotlinx.coroutines.launch
+
+object ShadeCarrierBinder {
+ /** Binds the view to the view-model, continuing to update the former based on the latter */
+ @JvmStatic
+ fun bind(
+ carrierTextView: AutoMarqueeTextView,
+ viewModel: ShadeCarrierGroupMobileIconViewModel,
+ ) {
+ carrierTextView.isVisible = true
+
+ carrierTextView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch { viewModel.carrierName.collect { carrierTextView.text = it } }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt
new file mode 100644
index 000000000000..f407127f3161
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.ShadeCarrierBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.util.AutoMarqueeTextView
+
+/**
+ * ViewGroup containing a mobile carrier name and icon in the Shade Header. Can be multiple
+ * instances as children under [ShadeCarrierGroup]
+ */
+class ModernShadeCarrierGroupMobileView(
+ context: Context,
+ attrs: AttributeSet?,
+) : LinearLayout(context, attrs) {
+
+ var subId: Int = -1
+
+ override fun toString(): String {
+ return "ModernShadeCarrierGroupMobileView(" +
+ "subId=$subId, " +
+ "viewString=${super.toString()}"
+ }
+
+ companion object {
+
+ /**
+ * Inflates a new instance of [ModernShadeCarrierGroupMobileView], binds it to [viewModel],
+ * and returns it.
+ */
+ @JvmStatic
+ fun constructAndBind(
+ context: Context,
+ logger: MobileViewLogger,
+ slot: String,
+ viewModel: ShadeCarrierGroupMobileIconViewModel,
+ ): ModernShadeCarrierGroupMobileView {
+ return (LayoutInflater.from(context).inflate(R.layout.shade_carrier_new, null)
+ as ModernShadeCarrierGroupMobileView)
+ .also {
+ it.subId = viewModel.subscriptionId
+
+ val iconView = it.requireViewById<ModernStatusBarMobileView>(R.id.mobile_combo)
+ iconView.initView(slot) {
+ MobileIconBinder.bind(iconView, viewModel, STATE_ICON, logger)
+ }
+ logger.logNewViewBinding(it, viewModel)
+
+ val textView = it.requireViewById<AutoMarqueeTextView>(R.id.mobile_carrier_text)
+ ShadeCarrierBinder.bind(textView, viewModel)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index 4144293d5ccd..68d02de51dc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -60,7 +60,9 @@ class ModernStatusBarMobileView(
as ModernStatusBarMobileView)
.also {
it.subId = viewModel.subscriptionId
- it.initView(slot) { MobileIconBinder.bind(it, viewModel, logger) }
+ it.initView(slot) {
+ MobileIconBinder.bind(view = it, viewModel = viewModel, logger = logger)
+ }
logger.logNewViewBinding(it, viewModel)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
index a51982c41255..e7c311d7ec74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
@@ -18,7 +18,13 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
import android.graphics.Color
import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
/**
* A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
@@ -26,12 +32,12 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
*
* @param commonImpl for convenience, this class wraps a base interface that can provides all of the
* common implementations between locations. See [MobileIconViewModel]
- * @property locationName the name of the location of this VM, used for logging.
+ * @property location the [StatusBarLocation] of this VM.
* @property verboseLogger an optional logger to log extremely verbose view updates.
*/
abstract class LocationBasedMobileViewModel(
val commonImpl: MobileIconViewModelCommon,
- val locationName: String,
+ val location: StatusBarLocation,
val verboseLogger: VerboseMobileViewLogger?,
) : MobileIconViewModelCommon by commonImpl {
val defaultColor: Int = Color.WHITE
@@ -39,10 +45,12 @@ abstract class LocationBasedMobileViewModel(
companion object {
fun viewModelForLocation(
commonImpl: MobileIconViewModelCommon,
+ interactor: MobileIconInteractor,
verboseMobileViewLogger: VerboseMobileViewLogger,
- loc: StatusBarLocation,
+ location: StatusBarLocation,
+ scope: CoroutineScope,
): LocationBasedMobileViewModel =
- when (loc) {
+ when (location) {
StatusBarLocation.HOME ->
HomeMobileIconViewModel(
commonImpl,
@@ -50,6 +58,12 @@ abstract class LocationBasedMobileViewModel(
)
StatusBarLocation.KEYGUARD -> KeyguardMobileIconViewModel(commonImpl)
StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl)
+ StatusBarLocation.SHADE_CARRIER_GROUP ->
+ ShadeCarrierGroupMobileIconViewModel(
+ commonImpl,
+ interactor,
+ scope,
+ )
}
}
}
@@ -61,7 +75,7 @@ class HomeMobileIconViewModel(
MobileIconViewModelCommon,
LocationBasedMobileViewModel(
commonImpl,
- locationName = "Home",
+ location = StatusBarLocation.HOME,
verboseMobileViewLogger,
)
@@ -71,18 +85,40 @@ class QsMobileIconViewModel(
MobileIconViewModelCommon,
LocationBasedMobileViewModel(
commonImpl,
- locationName = "QS",
+ location = StatusBarLocation.QS,
// Only do verbose logging for the Home location.
verboseLogger = null,
)
+class ShadeCarrierGroupMobileIconViewModel(
+ commonImpl: MobileIconViewModelCommon,
+ interactor: MobileIconInteractor,
+ scope: CoroutineScope,
+) :
+ MobileIconViewModelCommon,
+ LocationBasedMobileViewModel(
+ commonImpl,
+ location = StatusBarLocation.SHADE_CARRIER_GROUP,
+ // Only do verbose logging for the Home location.
+ verboseLogger = null,
+ ) {
+ private val isSingleCarrier = interactor.isSingleCarrier
+ val carrierName = interactor.carrierName
+
+ override val isVisible: StateFlow<Boolean> =
+ combine(super.isVisible, isSingleCarrier) { isVisible, isSingleCarrier ->
+ if (isSingleCarrier) false else isVisible
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), super.isVisible.value)
+}
+
class KeyguardMobileIconViewModel(
commonImpl: MobileIconViewModelCommon,
) :
MobileIconViewModelCommon,
LocationBasedMobileViewModel(
commonImpl,
- locationName = "Keyguard",
+ location = StatusBarLocation.KEYGUARD,
// Only do verbose logging for the Home location.
verboseLogger = null,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 5cf887e4d41a..216afb987f91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
@@ -58,6 +59,8 @@ constructor(
private val statusBarPipelineFlags: StatusBarPipelineFlags,
) {
@VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
+ @VisibleForTesting
+ val mobileIconInteractorSubIdCache = mutableMapOf<Int, MobileIconInteractor>()
val subscriptionIdsFlow: StateFlow<List<Int>> =
interactor.filteredSubscriptions
@@ -91,15 +94,17 @@ constructor(
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
init {
- scope.launch { subscriptionIdsFlow.collect { removeInvalidModelsFromCache(it) } }
+ scope.launch { subscriptionIdsFlow.collect { invalidateCaches(it) } }
}
fun viewModelForSub(subId: Int, location: StatusBarLocation): LocationBasedMobileViewModel {
val common = commonViewModelForSub(subId)
return LocationBasedMobileViewModel.viewModelForLocation(
common,
+ mobileIconInteractorForSub(subId),
verboseLogger,
location,
+ scope,
)
}
@@ -107,7 +112,7 @@ constructor(
return mobileIconSubIdCache[subId]
?: MobileIconViewModel(
subId,
- interactor.createMobileConnectionInteractorForSubId(subId),
+ mobileIconInteractorForSub(subId),
airplaneModeInteractor,
constants,
scope,
@@ -115,8 +120,20 @@ constructor(
.also { mobileIconSubIdCache[subId] = it }
}
- private fun removeInvalidModelsFromCache(subIds: List<Int>) {
+ @VisibleForTesting
+ fun mobileIconInteractorForSub(subId: Int): MobileIconInteractor {
+ return mobileIconInteractorSubIdCache[subId]
+ ?: interactor.createMobileConnectionInteractorForSubId(subId).also {
+ mobileIconInteractorSubIdCache[subId] = it
+ }
+ }
+
+ private fun invalidateCaches(subIds: List<Int>) {
val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) }
subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
+
+ mobileIconInteractorSubIdCache.keys
+ .filter { !subIds.contains(it) }
+ .forEach { subId -> mobileIconInteractorSubIdCache.remove(subId) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
index cd5b92cf24c7..00bd616e04ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
import android.graphics.Color
import com.android.systemui.statusbar.phone.StatusBarLocation
+import java.lang.IllegalArgumentException
/**
* A view model for a wifi icon in a specific location. This allows us to control parameters that
@@ -43,6 +44,8 @@ abstract class LocationBasedWifiViewModel(
StatusBarLocation.HOME -> HomeWifiViewModel(commonImpl)
StatusBarLocation.KEYGUARD -> KeyguardWifiViewModel(commonImpl)
StatusBarLocation.QS -> QsWifiViewModel(commonImpl)
+ StatusBarLocation.SHADE_CARRIER_GROUP ->
+ throw IllegalArgumentException("invalid location for WifiViewModel: $location")
}
}
}
@@ -64,3 +67,11 @@ class KeyguardWifiViewModel(
class QsWifiViewModel(
commonImpl: WifiViewModelCommon,
) : WifiViewModelCommon, LocationBasedWifiViewModel(commonImpl)
+
+/**
+ * A view model for the wifi icon in the shade carrier group (visible when quick settings is fully
+ * expanded, and in large screen shade). Currently unused.
+ */
+class ShadeCarrierGroupWifiViewModel(
+ commonImpl: WifiViewModelCommon,
+) : WifiViewModelCommon, LocationBasedWifiViewModel(commonImpl)
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index aea3030967d2..9dca013f8aa4 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -109,7 +109,6 @@ public class ImageWallpaper extends WallpaperService {
private WallpaperManager mWallpaperManager;
private final WallpaperLocalColorExtractor mWallpaperLocalColorExtractor;
private SurfaceHolder mSurfaceHolder;
- private boolean mDrawn = false;
@VisibleForTesting
static final int MIN_SURFACE_WIDTH = 128;
@VisibleForTesting
@@ -240,7 +239,6 @@ public class ImageWallpaper extends WallpaperService {
private void drawFrameSynchronized() {
synchronized (mLock) {
- if (mDrawn) return;
drawFrameInternal();
}
}
@@ -278,7 +276,6 @@ public class ImageWallpaper extends WallpaperService {
Rect dest = mSurfaceHolder.getSurfaceFrame();
try {
canvas.drawBitmap(bitmap, null, dest, null);
- mDrawn = true;
} finally {
surface.unlockCanvasAndPost(canvas);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index 98d4d22d59b4..1be87463250f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -23,7 +23,6 @@ import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLE
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -136,6 +135,10 @@ public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
+ mFakeDateView.setTag(R.id.tag_smartspace_view, new Object());
+ mFakeWeatherView.setTag(R.id.tag_smartspace_view, new Object());
+ mFakeSmartspaceView.setTag(R.id.tag_smartspace_view, new Object());
+
when(mView.findViewById(R.id.left_aligned_notification_icon_container))
.thenReturn(mNotificationIcons);
when(mNotificationIcons.getLayoutParams()).thenReturn(
@@ -158,12 +161,6 @@ public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
- doAnswer(invocation -> {
- removeView(mFakeDateView);
- removeView(mFakeWeatherView);
- removeView(mFakeSmartspaceView);
- return null;
- }).when(mSmartspaceController).removeViewsFromParent(any());
mExecutor = new FakeExecutor(new FakeSystemClock());
mFakeFeatureFlags = new FakeFeatureFlags();
mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 4e52e64a8af1..9584d888b01f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -39,13 +39,13 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
-import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
import com.android.systemui.flags.FakeFeatureFlags
@@ -109,6 +109,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val biometricPromptRepository = FakePromptRepository()
+ private val fingerprintRepository = FakeFingerprintPropertyRepository()
private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
private val credentialInteractor = FakeCredentialInteractor()
private val bpCredentialInteractor = PromptCredentialInteractor(
@@ -118,10 +119,12 @@ open class AuthContainerViewTest : SysuiTestCase() {
)
private val promptSelectorInteractor by lazy {
PromptSelectorInteractorImpl(
+ fingerprintRepository,
biometricPromptRepository,
lockPatternUtils,
)
}
+
private val displayStateInteractor = DisplayStateInteractorImpl(
testScope.backgroundScope,
mContext,
@@ -129,9 +132,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
rearDisplayStateRepository
)
- private val authBiometricFingerprintViewModel = AuthBiometricFingerprintViewModel(
- displayStateInteractor
- )
+
private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
private var authContainer: TestAuthContainerView? = null
@@ -524,10 +525,14 @@ open class AuthContainerViewTest : SysuiTestCase() {
userManager,
lockPatternUtils,
interactionJankMonitor,
- { authBiometricFingerprintViewModel },
{ promptSelectorInteractor },
{ bpCredentialInteractor },
- PromptViewModel(promptSelectorInteractor, vibrator, featureFlags),
+ PromptViewModel(
+ displayStateInteractor,
+ promptSelectorInteractor,
+ vibrator,
+ featureFlags
+ ),
{ credentialViewModel },
Handler(TestableLooper.get(this).looper),
fakeExecutor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 48e513140c3a..6d71dd5cd8ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -92,7 +92,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
-import com.android.systemui.biometrics.ui.viewmodel.AuthBiometricFingerprintViewModel;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -177,8 +176,6 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private PromptSelectorInteractor mPromptSelectionInteractor;
@Mock
- private AuthBiometricFingerprintViewModel mAuthBiometricFingerprintViewModel;
- @Mock
private CredentialViewModel mCredentialViewModel;
@Mock
private PromptViewModel mPromptViewModel;
@@ -1095,11 +1092,10 @@ public class AuthControllerTest extends SysuiTestCase {
mFingerprintManager, mFaceManager, () -> mUdfpsController,
() -> mSideFpsController, mDisplayManager, mWakefulnessLifecycle,
mPanelInteractionDetector, mUserManager, mLockPatternUtils, mUdfpsLogger,
- mLogContextInteractor, () -> mAuthBiometricFingerprintViewModel,
- () -> mBiometricPromptCredentialInteractor, () -> mPromptSelectionInteractor,
- () -> mCredentialViewModel, () -> mPromptViewModel,
- mInteractionJankMonitor, mHandler,
- mBackgroundExecutor, mUdfpsUtils, mVibratorHelper);
+ mLogContextInteractor, () -> mBiometricPromptCredentialInteractor,
+ () -> mPromptSelectionInteractor, () -> mCredentialViewModel,
+ () -> mPromptViewModel, mInteractionJankMonitor, mHandler, mBackgroundExecutor,
+ mUdfpsUtils, mVibratorHelper);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 81cbaeab2a32..4d5e1b7de60f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -23,6 +23,7 @@ import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.Utils
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.domain.model.BiometricModalities
import com.android.systemui.biometrics.faceSensorPropertiesInternal
@@ -61,13 +62,15 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() {
@Mock private lateinit var lockPatternUtils: LockPatternUtils
private val testScope = TestScope()
+ private val fingerprintRepository = FakeFingerprintPropertyRepository()
private val promptRepository = FakePromptRepository()
private lateinit var interactor: PromptSelectorInteractor
@Before
fun setup() {
- interactor = PromptSelectorInteractorImpl(promptRepository, lockPatternUtils)
+ interactor =
+ PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
index da55d5a099b7..95b72d554896 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
@@ -28,7 +28,7 @@ import org.junit.runners.Parameterized.Parameters
@SmallTest
@RunWith(Parameterized::class)
class BoundingBoxOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
- val underTest = BoundingBoxOverlapDetector()
+ val underTest = BoundingBoxOverlapDetector(1f)
@Test
fun isGoodOverlap() {
@@ -83,7 +83,7 @@ private val TOUCH_DATA =
GESTURE_START
)
-private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 500 /* bottom */)
+private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 400 /* bottom */)
private val OVERLAY = Rect(0 /* left */, 100 /* top */, 400 /* right */, 600 /* bottom */)
private fun genTestCases(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModelTest.kt
index 785f1be89986..7697c098ed3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/AuthBiometricFingerprintViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModelTest.kt
@@ -2,10 +2,17 @@ package com.android.systemui.biometrics.ui.viewmodel
import android.content.res.Configuration
import androidx.test.filters.SmallTest
+import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
+import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -16,39 +23,52 @@ import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
-class AuthBiometricFingerprintViewModelTest : SysuiTestCase() {
+class PromptFingerprintIconViewModelTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var lockPatternUtils: LockPatternUtils
+
+ private val fingerprintRepository = FakeFingerprintPropertyRepository()
+ private val promptRepository = FakePromptRepository()
private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
+
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
- private lateinit var interactor: DisplayStateInteractor
- private lateinit var viewModel: AuthBiometricFingerprintViewModel
+ private lateinit var promptSelectorInteractor: PromptSelectorInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var viewModel: PromptFingerprintIconViewModel
@Before
fun setup() {
- interactor =
+ promptSelectorInteractor =
+ PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
+ displayStateInteractor =
DisplayStateInteractorImpl(
testScope.backgroundScope,
mContext,
fakeExecutor,
rearDisplayStateRepository
)
- viewModel = AuthBiometricFingerprintViewModel(interactor)
+ viewModel = PromptFingerprintIconViewModel(displayStateInteractor, promptSelectorInteractor)
}
@Test
- fun iconUpdates_onConfigurationChanged() {
+ fun sfpsIconUpdates_onConfigurationChanged() {
testScope.runTest {
runCurrent()
-
+ configureFingerprintPropertyRepository(FingerprintSensorType.POWER_BUTTON)
val testConfig = Configuration()
val folded = INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP - 1
val unfolded = INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP + 1
@@ -65,6 +85,10 @@ class AuthBiometricFingerprintViewModelTest : SysuiTestCase() {
assertThat(foldedIcon).isNotEqualTo(unfoldedIcon)
}
}
+
+ private fun configureFingerprintPropertyRepository(sensorType: FingerprintSensorType) {
+ fingerprintRepository.setProperties(0, SensorStrength.STRONG, sensorType, mapOf())
+ }
}
internal const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 4d19543d41ff..11b0b0798ebc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -24,7 +24,10 @@ import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthBiometricView
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
+import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
import com.android.systemui.biometrics.domain.model.BiometricModalities
@@ -37,7 +40,9 @@ import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
@@ -69,8 +74,19 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
@Mock private lateinit var lockPatternUtils: LockPatternUtils
@Mock private lateinit var vibrator: VibratorHelper
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val testScope = TestScope()
+ private val fingerprintRepository = FakeFingerprintPropertyRepository()
private val promptRepository = FakePromptRepository()
+ private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
+
+ private val displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ rearDisplayStateRepository
+ )
private lateinit var selector: PromptSelectorInteractor
private lateinit var viewModel: PromptViewModel
@@ -78,10 +94,11 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
@Before
fun setup() {
- selector = PromptSelectorInteractorImpl(promptRepository, lockPatternUtils)
+ selector =
+ PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
selector.resetPrompt()
- viewModel = PromptViewModel(selector, vibrator, featureFlags)
+ viewModel = PromptViewModel(displayStateInteractor, selector, vibrator, featureFlags)
featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false)
}
@@ -105,7 +122,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
}
assertThat(message).isEqualTo(PromptMessage.Empty)
assertThat(size).isEqualTo(expectedSize)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN)
+ assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_IDLE)
val startMessage = "here we go"
viewModel.showAuthenticating(startMessage, isRetry = false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
index ff15cb39b640..14c5ec0361f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
@@ -29,6 +29,10 @@ import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.settings.GlobalSettings
import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.Serializable
+import java.io.StringWriter
+import java.util.function.Consumer
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@@ -41,44 +45,30 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations
-import java.io.PrintWriter
-import java.io.Serializable
-import java.io.StringWriter
-import java.util.function.Consumer
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
/**
* NOTE: This test is for the version of FeatureFlagManager in src-debug, which allows overriding
* the default.
*/
@SmallTest
-class FeatureFlagsDebugTest : SysuiTestCase() {
- private lateinit var featureFlagsDebug: FeatureFlagsDebug
-
- @Mock
- private lateinit var flagManager: FlagManager
- @Mock
- private lateinit var mockContext: Context
- @Mock
- private lateinit var globalSettings: GlobalSettings
- @Mock
- private lateinit var systemProperties: SystemPropertiesHelper
- @Mock
- private lateinit var resources: Resources
- @Mock
- private lateinit var restarter: Restarter
+class FeatureFlagsClassicDebugTest : SysuiTestCase() {
+ private lateinit var mFeatureFlagsClassicDebug: FeatureFlagsClassicDebug
+
+ @Mock private lateinit var flagManager: FlagManager
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var globalSettings: GlobalSettings
+ @Mock private lateinit var systemProperties: SystemPropertiesHelper
+ @Mock private lateinit var resources: Resources
+ @Mock private lateinit var restarter: Restarter
private val flagMap = mutableMapOf<String, Flag<*>>()
private lateinit var broadcastReceiver: BroadcastReceiver
private lateinit var clearCacheAction: Consumer<String>
private val serverFlagReader = ServerFlagReaderFake()
- private val teamfoodableFlagA = UnreleasedFlag(
- name = "a", namespace = "test", teamfood = true
- )
- private val teamfoodableFlagB = ReleasedFlag(
- name = "b", namespace = "test", teamfood = true
- )
+ private val teamfoodableFlagA = UnreleasedFlag(name = "a", namespace = "test", teamfood = true)
+ private val teamfoodableFlagB = ReleasedFlag(name = "b", namespace = "test", teamfood = true)
@Before
fun setup() {
@@ -86,27 +76,23 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
flagMap.put(Flags.TEAMFOOD.name, Flags.TEAMFOOD)
flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA)
flagMap.put(teamfoodableFlagB.name, teamfoodableFlagB)
- featureFlagsDebug = FeatureFlagsDebug(
- flagManager,
- mockContext,
- globalSettings,
- systemProperties,
- resources,
- serverFlagReader,
- flagMap,
- restarter
- )
- featureFlagsDebug.init()
+ mFeatureFlagsClassicDebug =
+ FeatureFlagsClassicDebug(
+ flagManager,
+ mockContext,
+ globalSettings,
+ systemProperties,
+ resources,
+ serverFlagReader,
+ flagMap,
+ restarter
+ )
+ mFeatureFlagsClassicDebug.init()
verify(flagManager).onSettingsChangedAction = any()
broadcastReceiver = withArgCaptor {
- verify(mockContext).registerReceiver(
- capture(), any(), nullable(), nullable(),
- any()
- )
- }
- clearCacheAction = withArgCaptor {
- verify(flagManager).clearCacheAction = capture()
+ verify(mockContext).registerReceiver(capture(), any(), nullable(), nullable(), any())
}
+ clearCacheAction = withArgCaptor { verify(flagManager).clearCacheAction = capture() }
whenever(flagManager.nameToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" }
}
@@ -117,45 +103,29 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(flagManager.readFlagValue<Boolean>(eq("4"), any())).thenReturn(false)
assertThat(
- featureFlagsDebug.isEnabled(
- ReleasedFlag(
- name = "2",
- namespace = "test"
- )
+ mFeatureFlagsClassicDebug.isEnabled(ReleasedFlag(name = "2", namespace = "test"))
)
- ).isTrue()
+ .isTrue()
assertThat(
- featureFlagsDebug.isEnabled(
- UnreleasedFlag(
- name = "3",
- namespace = "test"
- )
+ mFeatureFlagsClassicDebug.isEnabled(UnreleasedFlag(name = "3", namespace = "test"))
)
- ).isTrue()
+ .isTrue()
assertThat(
- featureFlagsDebug.isEnabled(
- ReleasedFlag(
- name = "4",
- namespace = "test"
- )
+ mFeatureFlagsClassicDebug.isEnabled(ReleasedFlag(name = "4", namespace = "test"))
)
- ).isFalse()
+ .isFalse()
assertThat(
- featureFlagsDebug.isEnabled(
- UnreleasedFlag(
- name = "5",
- namespace = "test"
- )
+ mFeatureFlagsClassicDebug.isEnabled(UnreleasedFlag(name = "5", namespace = "test"))
)
- ).isFalse()
+ .isFalse()
}
@Test
fun teamFoodFlag_False() {
- whenever(flagManager.readFlagValue<Boolean>(
- eq(Flags.TEAMFOOD.name), any())).thenReturn(false)
- assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
- assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+ whenever(flagManager.readFlagValue<Boolean>(eq(Flags.TEAMFOOD.name), any()))
+ .thenReturn(false)
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isFalse()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isTrue()
// Regular boolean flags should still test the same.
// Only our teamfoodableFlag should change.
@@ -164,10 +134,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun teamFoodFlag_True() {
- whenever(flagManager.readFlagValue<Boolean>(
- eq(Flags.TEAMFOOD.name), any())).thenReturn(true)
- assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
- assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+ whenever(flagManager.readFlagValue<Boolean>(eq(Flags.TEAMFOOD.name), any()))
+ .thenReturn(true)
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isTrue()
// Regular boolean flags should still test the same.
// Only our teamfoodableFlag should change.
@@ -180,10 +150,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
.thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.name), any()))
.thenReturn(false)
- whenever(flagManager.readFlagValue<Boolean>(
- eq(Flags.TEAMFOOD.name), any())).thenReturn(true)
- assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
- assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
+ whenever(flagManager.readFlagValue<Boolean>(eq(Flags.TEAMFOOD.name), any()))
+ .thenReturn(true)
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isFalse()
// Regular boolean flags should still test the same.
// Only our teamfoodableFlag should change.
@@ -201,25 +171,20 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(flagManager.readFlagValue<Boolean>(eq("3"), any())).thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq("5"), any())).thenReturn(false)
- assertThat(
- featureFlagsDebug.isEnabled(
- ResourceBooleanFlag(
- "1",
- "test",
- 1001
- )
- )
- ).isFalse()
- assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag("2", "test", 1002))).isTrue()
- assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag("3", "test", 1003))).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(ResourceBooleanFlag("1", "test", 1001)))
+ .isFalse()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(ResourceBooleanFlag("2", "test", 1002)))
+ .isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(ResourceBooleanFlag("3", "test", 1003)))
+ .isTrue()
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.isEnabled(ResourceBooleanFlag("4", "test", 1004))
+ mFeatureFlagsClassicDebug.isEnabled(ResourceBooleanFlag("4", "test", 1004))
}
// Test that resource is loaded (and validated) even when the setting is set.
// This prevents developers from not noticing when they reference an invalid resource.
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.isEnabled(ResourceBooleanFlag("5", "test", 1005))
+ mFeatureFlagsClassicDebug.isEnabled(ResourceBooleanFlag("5", "test", 1005))
}
}
@@ -232,29 +197,27 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
return@thenAnswer it.getArgument(1)
}
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("a", "test"))).isFalse()
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("b", "test"))).isTrue()
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("c", "test", true))).isTrue()
- assertThat(
- featureFlagsDebug.isEnabled(
- SysPropBooleanFlag(
- "d",
- "test",
- false
- )
- )
- ).isFalse()
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("e", "test"))).isFalse()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(SysPropBooleanFlag("a", "test"))).isFalse()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(SysPropBooleanFlag("b", "test"))).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(SysPropBooleanFlag("c", "test", true)))
+ .isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(SysPropBooleanFlag("d", "test", false)))
+ .isFalse()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(SysPropBooleanFlag("e", "test"))).isFalse()
}
@Test
fun readStringFlag() {
whenever(flagManager.readFlagValue<String>(eq("3"), any())).thenReturn("foo")
whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("bar")
- assertThat(featureFlagsDebug.getString(StringFlag("1", "test", "biz"))).isEqualTo("biz")
- assertThat(featureFlagsDebug.getString(StringFlag("2", "test", "baz"))).isEqualTo("baz")
- assertThat(featureFlagsDebug.getString(StringFlag("3", "test", "buz"))).isEqualTo("foo")
- assertThat(featureFlagsDebug.getString(StringFlag("4", "test", "buz"))).isEqualTo("bar")
+ assertThat(mFeatureFlagsClassicDebug.getString(StringFlag("1", "test", "biz")))
+ .isEqualTo("biz")
+ assertThat(mFeatureFlagsClassicDebug.getString(StringFlag("2", "test", "baz")))
+ .isEqualTo("baz")
+ assertThat(mFeatureFlagsClassicDebug.getString(StringFlag("3", "test", "buz")))
+ .isEqualTo("foo")
+ assertThat(mFeatureFlagsClassicDebug.getString(StringFlag("4", "test", "buz")))
+ .isEqualTo("bar")
}
@Test
@@ -270,44 +233,23 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("override4")
whenever(flagManager.readFlagValue<String>(eq("6"), any())).thenReturn("override6")
- assertThat(
- featureFlagsDebug.getString(
- ResourceStringFlag(
- "1",
- "test",
- 1001
- )
- )
- ).isEqualTo("")
- assertThat(
- featureFlagsDebug.getString(
- ResourceStringFlag(
- "2",
- "test",
- 1002
- )
- )
- ).isEqualTo("resource2")
- assertThat(
- featureFlagsDebug.getString(
- ResourceStringFlag(
- "3",
- "test",
- 1003
- )
- )
- ).isEqualTo("override3")
+ assertThat(mFeatureFlagsClassicDebug.getString(ResourceStringFlag("1", "test", 1001)))
+ .isEqualTo("")
+ assertThat(mFeatureFlagsClassicDebug.getString(ResourceStringFlag("2", "test", 1002)))
+ .isEqualTo("resource2")
+ assertThat(mFeatureFlagsClassicDebug.getString(ResourceStringFlag("3", "test", 1003)))
+ .isEqualTo("override3")
Assert.assertThrows(NullPointerException::class.java) {
- featureFlagsDebug.getString(ResourceStringFlag("4", "test", 1004))
+ mFeatureFlagsClassicDebug.getString(ResourceStringFlag("4", "test", 1004))
}
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.getString(ResourceStringFlag("5", "test", 1005))
+ mFeatureFlagsClassicDebug.getString(ResourceStringFlag("5", "test", 1005))
}
// Test that resource is loaded (and validated) even when the setting is set.
// This prevents developers from not noticing when they reference an invalid resource.
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.getString(ResourceStringFlag("6", "test", 1005))
+ mFeatureFlagsClassicDebug.getString(ResourceStringFlag("6", "test", 1005))
}
}
@@ -315,10 +257,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
fun readIntFlag() {
whenever(flagManager.readFlagValue<Int>(eq("3"), any())).thenReturn(22)
whenever(flagManager.readFlagValue<Int>(eq("4"), any())).thenReturn(48)
- assertThat(featureFlagsDebug.getInt(IntFlag("1", "test", 12))).isEqualTo(12)
- assertThat(featureFlagsDebug.getInt(IntFlag("2", "test", 93))).isEqualTo(93)
- assertThat(featureFlagsDebug.getInt(IntFlag("3", "test", 8))).isEqualTo(22)
- assertThat(featureFlagsDebug.getInt(IntFlag("4", "test", 234))).isEqualTo(48)
+ assertThat(mFeatureFlagsClassicDebug.getInt(IntFlag("1", "test", 12))).isEqualTo(12)
+ assertThat(mFeatureFlagsClassicDebug.getInt(IntFlag("2", "test", 93))).isEqualTo(93)
+ assertThat(mFeatureFlagsClassicDebug.getInt(IntFlag("3", "test", 8))).isEqualTo(22)
+ assertThat(mFeatureFlagsClassicDebug.getInt(IntFlag("4", "test", 234))).isEqualTo(48)
}
@Test
@@ -334,17 +276,20 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(flagManager.readFlagValue<Int>(eq("4"), any())).thenReturn(500)
whenever(flagManager.readFlagValue<Int>(eq("5"), any())).thenReturn(9519)
- assertThat(featureFlagsDebug.getInt(ResourceIntFlag("1", "test", 1001))).isEqualTo(88)
- assertThat(featureFlagsDebug.getInt(ResourceIntFlag("2", "test", 1002))).isEqualTo(61)
- assertThat(featureFlagsDebug.getInt(ResourceIntFlag("3", "test", 1003))).isEqualTo(20)
+ assertThat(mFeatureFlagsClassicDebug.getInt(ResourceIntFlag("1", "test", 1001)))
+ .isEqualTo(88)
+ assertThat(mFeatureFlagsClassicDebug.getInt(ResourceIntFlag("2", "test", 1002)))
+ .isEqualTo(61)
+ assertThat(mFeatureFlagsClassicDebug.getInt(ResourceIntFlag("3", "test", 1003)))
+ .isEqualTo(20)
Assert.assertThrows(NotFoundException::class.java) {
- featureFlagsDebug.getInt(ResourceIntFlag("4", "test", 1004))
+ mFeatureFlagsClassicDebug.getInt(ResourceIntFlag("4", "test", 1004))
}
// Test that resource is loaded (and validated) even when the setting is set.
// This prevents developers from not noticing when they reference an invalid resource.
Assert.assertThrows(NotFoundException::class.java) {
- featureFlagsDebug.getInt(ResourceIntFlag("5", "test", 1005))
+ mFeatureFlagsClassicDebug.getInt(ResourceIntFlag("5", "test", 1005))
}
}
@@ -424,11 +369,11 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("original")
// gets the flag & cache it
- assertThat(featureFlagsDebug.getString(flag1)).isEqualTo("original")
+ assertThat(mFeatureFlagsClassicDebug.getString(flag1)).isEqualTo("original")
verify(flagManager, times(1)).readFlagValue(eq("1"), eq(StringFlagSerializer))
// hit the cache
- assertThat(featureFlagsDebug.getString(flag1)).isEqualTo("original")
+ assertThat(mFeatureFlagsClassicDebug.getString(flag1)).isEqualTo("original")
verifyNoMoreInteractions(flagManager)
// set the flag
@@ -436,7 +381,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
verifyPutData("1", "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2)
whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("new")
- assertThat(featureFlagsDebug.getString(flag1)).isEqualTo("new")
+ assertThat(mFeatureFlagsClassicDebug.getString(flag1)).isEqualTo("new")
verify(flagManager, times(3)).readFlagValue(eq("1"), eq(StringFlagSerializer))
}
@@ -446,7 +391,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
- assertThat(featureFlagsDebug.isEnabled(flag)).isFalse()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(flag)).isFalse()
}
@Test
@@ -454,32 +399,41 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
val flag = UnreleasedFlag(name = "100", namespace = "test")
serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
- assertThat(featureFlagsDebug.isEnabled(flag)).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(flag)).isTrue()
}
@Test
fun serverSide_OverrideUncached_NoRestart() {
// No one has read the flag, so it's not in the cache.
serverFlagReader.setFlagValue(
- teamfoodableFlagA.namespace, teamfoodableFlagA.name, !teamfoodableFlagA.default)
+ teamfoodableFlagA.namespace,
+ teamfoodableFlagA.name,
+ !teamfoodableFlagA.default
+ )
verify(restarter, never()).restartSystemUI(anyString())
}
@Test
fun serverSide_Override_Restarts() {
// Read it to put it in the cache.
- featureFlagsDebug.isEnabled(teamfoodableFlagA)
+ mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)
serverFlagReader.setFlagValue(
- teamfoodableFlagA.namespace, teamfoodableFlagA.name, !teamfoodableFlagA.default)
+ teamfoodableFlagA.namespace,
+ teamfoodableFlagA.name,
+ !teamfoodableFlagA.default
+ )
verify(restarter).restartSystemUI(anyString())
}
@Test
fun serverSide_RedundantOverride_NoRestart() {
// Read it to put it in the cache.
- featureFlagsDebug.isEnabled(teamfoodableFlagA)
+ mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)
serverFlagReader.setFlagValue(
- teamfoodableFlagA.namespace, teamfoodableFlagA.name, teamfoodableFlagA.default)
+ teamfoodableFlagA.namespace,
+ teamfoodableFlagA.name,
+ teamfoodableFlagA.default
+ )
verify(restarter, never()).restartSystemUI(anyString())
}
@@ -500,13 +454,13 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
.thenReturn("override7")
// WHEN the flags have been accessed
- assertThat(featureFlagsDebug.isEnabled(flag1)).isTrue()
- assertThat(featureFlagsDebug.isEnabled(flag2)).isTrue()
- assertThat(featureFlagsDebug.isEnabled(flag3)).isFalse()
- assertThat(featureFlagsDebug.getString(flag4)).isEmpty()
- assertThat(featureFlagsDebug.getString(flag5)).isEqualTo("flag5default")
- assertThat(featureFlagsDebug.getString(flag6)).isEqualTo("resource1006")
- assertThat(featureFlagsDebug.getString(flag7)).isEqualTo("override7")
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(flag1)).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(flag2)).isTrue()
+ assertThat(mFeatureFlagsClassicDebug.isEnabled(flag3)).isFalse()
+ assertThat(mFeatureFlagsClassicDebug.getString(flag4)).isEmpty()
+ assertThat(mFeatureFlagsClassicDebug.getString(flag5)).isEqualTo("flag5default")
+ assertThat(mFeatureFlagsClassicDebug.getString(flag6)).isEqualTo("resource1006")
+ assertThat(mFeatureFlagsClassicDebug.getString(flag7)).isEqualTo("override7")
// THEN the dump contains the flags and the default values
val dump = dumpToString()
@@ -520,12 +474,15 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
}
private fun verifyPutData(name: String, data: String, numReads: Int = 1) {
- inOrder(flagManager, globalSettings).apply {
- verify(flagManager, times(numReads)).readFlagValue(eq(name), any<FlagSerializer<*>>())
- verify(flagManager).nameToSettingsKey(eq(name))
- verify(globalSettings).putStringForUser(eq("key-$name"), eq(data), anyInt())
- verify(flagManager).dispatchListenersAndMaybeRestart(eq(name), any())
- }.verifyNoMoreInteractions()
+ inOrder(flagManager, globalSettings)
+ .apply {
+ verify(flagManager, times(numReads))
+ .readFlagValue(eq(name), any<FlagSerializer<*>>())
+ verify(flagManager).nameToSettingsKey(eq(name))
+ verify(globalSettings).putStringForUser(eq("key-$name"), eq(data), anyInt())
+ verify(flagManager).dispatchListenersAndMaybeRestart(eq(name), any())
+ }
+ .verifyNoMoreInteractions()
verifyNoMoreInteractions(flagManager, globalSettings)
}
@@ -545,7 +502,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
private fun dumpToString(): String {
val sw = StringWriter()
val pw = PrintWriter(sw)
- featureFlagsDebug.dump(pw, emptyArray<String>())
+ mFeatureFlagsClassicDebug.dump(pw, emptyArray<String>())
pw.flush()
return sw.toString()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
index 16b459556cb9..70d6dd93459e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
@@ -26,16 +26,16 @@ import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.never
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
/**
* NOTE: This test is for the version of FeatureFlagManager in src-release, which should not allow
* overriding, and should never return any value other than the one provided as the default.
*/
@SmallTest
-class FeatureFlagsReleaseTest : SysuiTestCase() {
- private lateinit var featureFlagsRelease: FeatureFlagsRelease
+class FeatureFlagsClassicReleaseTest : SysuiTestCase() {
+ private lateinit var mFeatureFlagsClassicRelease: FeatureFlagsClassicRelease
@Mock private lateinit var mResources: Resources
@Mock private lateinit var mSystemProperties: SystemPropertiesHelper
@@ -43,21 +43,22 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
private val flagMap = mutableMapOf<String, Flag<*>>()
private val serverFlagReader = ServerFlagReaderFake()
-
private val flagA = ReleasedFlag(name = "a", namespace = "test")
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
flagMap.put(flagA.name, flagA)
- featureFlagsRelease = FeatureFlagsRelease(
- mResources,
- mSystemProperties,
- serverFlagReader,
- flagMap,
- restarter)
-
- featureFlagsRelease.init()
+ mFeatureFlagsClassicRelease =
+ FeatureFlagsClassicRelease(
+ mResources,
+ mSystemProperties,
+ serverFlagReader,
+ flagMap,
+ restarter
+ )
+
+ mFeatureFlagsClassicRelease.init()
}
@Test
@@ -67,7 +68,7 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
val flagNamespace = "test"
val flag = ResourceBooleanFlag(flagName, flagNamespace, flagResourceId)
whenever(mResources.getBoolean(flagResourceId)).thenReturn(true)
- assertThat(featureFlagsRelease.isEnabled(flag)).isTrue()
+ assertThat(mFeatureFlagsClassicRelease.isEnabled(flag)).isTrue()
}
@Test
@@ -77,16 +78,16 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
whenever(mResources.getString(1003)).thenReturn(null)
whenever(mResources.getString(1004)).thenAnswer { throw NameNotFoundException() }
- assertThat(featureFlagsRelease.getString(
- ResourceStringFlag("1", "test", 1001))).isEqualTo("")
- assertThat(featureFlagsRelease.getString(
- ResourceStringFlag("2", "test", 1002))).isEqualTo("res2")
+ assertThat(mFeatureFlagsClassicRelease.getString(ResourceStringFlag("1", "test", 1001)))
+ .isEqualTo("")
+ assertThat(mFeatureFlagsClassicRelease.getString(ResourceStringFlag("2", "test", 1002)))
+ .isEqualTo("res2")
assertThrows(NullPointerException::class.java) {
- featureFlagsRelease.getString(ResourceStringFlag("3", "test", 1003))
+ mFeatureFlagsClassicRelease.getString(ResourceStringFlag("3", "test", 1003))
}
assertThrows(NameNotFoundException::class.java) {
- featureFlagsRelease.getString(ResourceStringFlag("4", "test", 1004))
+ mFeatureFlagsClassicRelease.getString(ResourceStringFlag("4", "test", 1004))
}
}
@@ -98,7 +99,7 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
val flag = SysPropBooleanFlag(flagName, flagNamespace, flagDefault)
whenever(mSystemProperties.getBoolean(flagName, flagDefault)).thenReturn(flagDefault)
- assertThat(featureFlagsRelease.isEnabled(flag)).isEqualTo(flagDefault)
+ assertThat(mFeatureFlagsClassicRelease.isEnabled(flag)).isEqualTo(flagDefault)
}
@Test
@@ -107,7 +108,7 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
- assertThat(featureFlagsRelease.isEnabled(flag)).isFalse()
+ assertThat(mFeatureFlagsClassicRelease.isEnabled(flag)).isFalse()
}
@Test
@@ -116,32 +117,29 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
- assertThat(featureFlagsRelease.isEnabled(flag)).isFalse()
+ assertThat(mFeatureFlagsClassicRelease.isEnabled(flag)).isFalse()
}
@Test
fun serverSide_OverrideUncached_NoRestart() {
// No one has read the flag, so it's not in the cache.
- serverFlagReader.setFlagValue(
- flagA.namespace, flagA.name, !flagA.default)
+ serverFlagReader.setFlagValue(flagA.namespace, flagA.name, !flagA.default)
Mockito.verify(restarter, never()).restartSystemUI(Mockito.anyString())
}
@Test
fun serverSide_Override_Restarts() {
// Read it to put it in the cache.
- featureFlagsRelease.isEnabled(flagA)
- serverFlagReader.setFlagValue(
- flagA.namespace, flagA.name, !flagA.default)
+ mFeatureFlagsClassicRelease.isEnabled(flagA)
+ serverFlagReader.setFlagValue(flagA.namespace, flagA.name, !flagA.default)
Mockito.verify(restarter).restartSystemUI(Mockito.anyString())
}
@Test
fun serverSide_RedundantOverride_NoRestart() {
// Read it to put it in the cache.
- featureFlagsRelease.isEnabled(flagA)
- serverFlagReader.setFlagValue(
- flagA.namespace, flagA.name, flagA.default)
+ mFeatureFlagsClassicRelease.isEnabled(flagA)
+ serverFlagReader.setFlagValue(flagA.namespace, flagA.name, flagA.default)
Mockito.verify(restarter, never()).restartSystemUI(Mockito.anyString())
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
index b02baa7fd1b5..7c1325e2b355 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
@@ -30,7 +30,7 @@ import org.mockito.MockitoAnnotations
@SmallTest
class FlagCommandTest : SysuiTestCase() {
- @Mock private lateinit var featureFlags: FeatureFlagsDebug
+ @Mock private lateinit var featureFlags: FeatureFlagsClassicDebug
@Mock private lateinit var pw: PrintWriter
private val flagMap = mutableMapOf<String, Flag<*>>()
private val flagA = UnreleasedFlag("500", "test")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 6aa5a00c36da..b1cf0517ddd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -70,10 +71,10 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
@@ -89,7 +90,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
-import java.util.Optional;
import java.util.concurrent.Executor;
@SmallTest
@@ -119,6 +119,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
@Mock private IStatusBarService mStatusBarService;
@Mock private LightBarController mLightBarController;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock private StatusBarWindowController mStatusBarWindowController;
@Mock private IWindowManager mWindowManager;
@Mock private Executor mBackgroundExecutor;
@Mock private UiEventLogger mUiEventLogger;
@@ -128,7 +129,6 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
@Mock private Handler mHandler;
@Mock private UserContextProvider mUserContextProvider;
@Mock private VibratorHelper mVibratorHelper;
- @Mock private CentralSurfaces mCentralSurfaces;
@Mock private ShadeController mShadeController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
@@ -172,13 +172,13 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
mStatusBarService,
mLightBarController,
mNotificationShadeWindowController,
+ mStatusBarWindowController,
mWindowManager,
mBackgroundExecutor,
mUiEventLogger,
mRingerModeTracker,
mHandler,
mPackageManager,
- Optional.of(mCentralSurfaces),
mShadeController,
mKeyguardUpdateMonitor,
mDialogLaunchAnimator);
@@ -305,7 +305,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
- doReturn(true).when(mCentralSurfaces).isKeyguardShowing();
+ doReturn(true).when(mKeyguardStateController).isShowing();
String[] actions = {
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
@@ -329,7 +329,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
- doReturn(false).when(mCentralSurfaces).isKeyguardShowing();
+ doReturn(false).when(mKeyguardStateController).isShowing();
String[] actions = {
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
@@ -348,6 +348,34 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
}
@Test
+ public void testSwipeDown_pastStatusBarHeight_shadeNotOpened() {
+ mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+ doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+ doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+ doReturn(false).when(mKeyguardStateController).isShowing();
+ String[] actions = {
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+ GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
+
+ doReturn(100).when(mStatusBarWindowController).getStatusBarHeight();
+
+ GestureDetector.SimpleOnGestureListener gestureListener = spy(dialog.mGestureListener);
+ // WHEN the start y is larger than the status bar height
+ MotionEvent start = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 200, 0);
+ MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0);
+ gestureListener.onFling(start, end, 0, 1000);
+
+ // THEN the shade isn't opened
+ verify(mShadeController, never()).animateExpandShade();
+ }
+
+ @Test
public void testShouldLogBugreportPress() throws InterruptedException {
GlobalActionsDialogLite.BugReportAction bugReportAction =
mGlobalActionsDialogLite.makeBugReportActionForTesting();
@@ -539,7 +567,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
- doReturn(false).when(mCentralSurfaces).isKeyguardShowing();
+ doReturn(false).when(mKeyguardStateController).isShowing();
String[] actions = {
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
index a3f7fc5fc8cf..e0ae0c359f07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -131,14 +131,12 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
}
@Test
- fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_collapsesShade() {
+ fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_showsPrimaryBouncer() {
keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
- val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
- assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
- verify(shadeController).animateCollapseShadeForced()
+ verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_MENU)
}
@Test
@@ -147,42 +145,48 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
- // action down: does NOT collapse the shade
- val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)
- assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
- verify(shadeController, never()).animateCollapseShadeForced()
-
- // action up: collapses the shade
- val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
- assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
- verify(shadeController).animateCollapseShadeForced()
+ verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU)
}
@Test
- fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_neverCollapsesShade() {
+ fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_doNothing() {
keyguardInteractorWithDependencies.repository.setWakefulnessModel(asleepWakefulnessMode)
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
- val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
- assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse()
- verify(shadeController, never()).animateCollapseShadeForced()
+ verifyActionsDoNothing(KeyEvent.KEYCODE_MENU)
}
@Test
- fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_collapsesShade() {
+ fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_showsPrimaryBouncer() {
keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- // action down: does NOT collapse the shade
- val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)
- assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
- verify(shadeController, never()).animateCollapseShadeForced()
+ verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_SPACE)
+ }
- // action up: collapses the shade
- val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE)
- assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
- verify(shadeController).animateCollapseShadeForced()
+ @Test
+ fun dispatchKeyEvent_spaceActionUp_shadeLocked_collapsesShade() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+
+ verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_SPACE)
+ }
+
+ @Test
+ fun dispatchKeyEvent_enterActionUp_interactiveKeyguard_showsPrimaryBouncer() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+ verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_ENTER)
+ }
+
+ @Test
+ fun dispatchKeyEvent_enterActionUp_shadeLocked_collapsesShade() {
+ keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+
+ verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_ENTER)
}
@Test
@@ -252,4 +256,42 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
.isFalse()
verify(statusBarKeyguardViewManager, never()).interceptMediaKey(any())
}
+
+ private fun verifyActionUpCollapsesTheShade(keycode: Int) {
+ // action down: does NOT collapse the shade
+ val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+ verify(shadeController, never()).animateCollapseShadeForced()
+
+ // action up: collapses the shade
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+ verify(shadeController).animateCollapseShadeForced()
+ }
+
+ private fun verifyActionUpShowsPrimaryBouncer(keycode: Int) {
+ // action down: does NOT collapse the shade
+ val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+ verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+
+ // action up: collapses the shade
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+ verify(statusBarKeyguardViewManager).showPrimaryBouncer(eq(true))
+ }
+
+ private fun verifyActionsDoNothing(keycode: Int) {
+ // action down: does nothing
+ val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+ verify(shadeController, never()).animateCollapseShadeForced()
+ verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+
+ // action up: doesNothing
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse()
+ verify(shadeController, never()).animateCollapseShadeForced()
+ verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt
index 6c96576bcbc1..a9f8ea0194c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt
@@ -36,8 +36,8 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -54,6 +54,7 @@ class CustomTileStatePersisterTest : SysuiTestCase() {
private const val TEST_SUBTITLE = "test_subtitle"
private const val TEST_CONTENT_DESCRIPTION = "test_content_description"
private const val TEST_STATE_DESCRIPTION = "test_state_description"
+ private const val TEST_DEFAULT_LABEL = "default_label"
private fun Tile.isEqualTo(other: Tile): Boolean {
return state == other.state &&
@@ -156,4 +157,14 @@ class CustomTileStatePersisterTest : SysuiTestCase() {
verify(editor).remove(KEY.toString())
}
+
+ @Test
+ fun testWithDefaultLabel_notStored() {
+ tile.setDefaultLabel(TEST_DEFAULT_LABEL)
+
+ `when`(sharedPreferences.getString(eq(KEY.toString()), any()))
+ .thenReturn(writeToString(tile))
+
+ assertThat(customTileStatePersister.readState(KEY)!!.label).isNull()
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 41240e51c9fc..244f627c46b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -25,6 +25,7 @@ import android.content.pm.ServiceInfo
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.os.Handler
+import android.os.Parcel
import android.service.quicksettings.IQSTileService
import android.service.quicksettings.Tile
import android.test.suitebuilder.annotation.SmallTest
@@ -33,6 +34,7 @@ import android.testing.TestableLooper
import android.view.IWindowManager
import android.view.View
import com.android.internal.logging.MetricsLogger
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.view.LaunchableFrameLayout
@@ -47,6 +49,7 @@ import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
+import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertThrows
@@ -395,4 +398,45 @@ class CustomTileTest : SysuiTestCase() {
verify(tileServiceManager, never()).setBindRequested(true)
verify(tileService, never()).onStartListening()
}
+
+ @Test
+ fun testAlwaysUseDefaultLabelIfNoLabelIsSet() {
+ // Give it an icon to prevent issues
+ serviceInfo.icon = R.drawable.android
+
+ val label1 = "Label 1"
+ val label2 = "Label 2"
+
+ `when`(serviceInfo.loadLabel(any())).thenReturn(label1)
+ customTile.handleSetListening(true)
+ testableLooper.processAllMessages()
+ customTile.handleSetListening(false)
+ testableLooper.processAllMessages()
+
+ assertThat(customTile.state.label).isEqualTo(label1)
+
+ // Retrieve the tile as if bound (a separate copy)
+ val tile = copyTileUsingParcel(customTile.qsTile)
+
+ // Change the language
+ `when`(serviceInfo.loadLabel(any())).thenReturn(label2)
+
+ // Set the tile to listening and apply the tile (unmodified)
+ customTile.handleSetListening(true)
+ testableLooper.processAllMessages()
+ customTile.updateTileState(tile)
+ customTile.refreshState()
+ testableLooper.processAllMessages()
+
+ assertThat(customTile.state.label).isEqualTo(label2)
+ }
+
+ private fun copyTileUsingParcel(t: Tile): Tile {
+ val parcel = Parcel.obtain()
+ parcel.setDataPosition(0)
+ t.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+
+ return Tile.CREATOR.createFromParcel(parcel)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
index cbc355380568..d1d3c17be67f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
@@ -26,8 +26,6 @@ import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.classifier.FalsingManagerFake
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
@@ -74,8 +72,6 @@ class FontScalingTileTest : SysuiTestCase() {
private lateinit var backgroundDelayableExecutor: FakeExecutor
private lateinit var fontScalingTile: FontScalingTile
- val featureFlags = FakeFeatureFlags()
-
@Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>
@Before
@@ -102,7 +98,6 @@ class FontScalingTileTest : SysuiTestCase() {
FakeSettings(),
FakeSettings(),
FakeSystemClock(),
- featureFlags,
userTracker,
backgroundDelayableExecutor,
)
@@ -117,18 +112,7 @@ class FontScalingTileTest : SysuiTestCase() {
}
@Test
- fun isAvailable_whenFlagIsFalse_returnsFalse() {
- featureFlags.set(Flags.ENABLE_FONT_SCALING_TILE, false)
-
- val isAvailable = fontScalingTile.isAvailable()
-
- assertThat(isAvailable).isFalse()
- }
-
- @Test
- fun isAvailable_whenFlagIsTrue_returnsTrue() {
- featureFlags.set(Flags.ENABLE_FONT_SCALING_TILE, true)
-
+ fun isAvailable_alwaysReturnsTrue() {
val isAvailable = fontScalingTile.isAvailable()
assertThat(isAvailable).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 3e20511d6278..60988091a79a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -60,6 +60,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.wifi.WifiUtils;
+import com.android.settingslib.wifi.dpp.WifiDppIntentHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
@@ -190,6 +191,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
public void setUp() {
mStaticMockSession = mockitoSession()
.mockStatic(SubscriptionManager.class)
+ .mockStatic(WifiDppIntentHelper.class)
.strictness(Strictness.LENIENT)
.startMocking();
MockitoAnnotations.initMocks(this);
@@ -230,6 +232,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
mInternetDialogController.mActivityStarter = mActivityStarter;
mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
mFlags.set(Flags.QS_SECONDARY_DATA_SUB_INFO, false);
+ mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, false);
mConfig = new Configuration(mContext.getResources().getConfiguration());
Configuration c2 = new Configuration(mConfig);
@@ -973,6 +976,29 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
+ public void getConfiguratorQrCodeGeneratorIntentOrNull_wifiNotShareable_returnNull() {
+ mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, true);
+ when(mConnectedEntry.canShare()).thenReturn(false);
+ assertThat(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+ mConnectedEntry)).isNull();
+ }
+ @Test
+ public void getConfiguratorQrCodeGeneratorIntentOrNull_flagOff_returnNull() {
+ mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, false);
+ when(mConnectedEntry.canShare()).thenReturn(true);
+ assertThat(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+ mConnectedEntry)).isNull();
+ }
+
+ @Test
+ public void getConfiguratorQrCodeGeneratorIntentOrNull_wifiShareable() {
+ mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, true);
+ when(mConnectedEntry.canShare()).thenReturn(true);
+ assertThat(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+ mConnectedEntry)).isNotNull();
+ }
+
+ @Test
public void onStop_cleanUp() {
doReturn(SUB_ID).when(mTelephonyManager).getSubscriptionId();
assertThat(mInternetDialogController.mSubIdTelephonyManagerMap.get(SUB_ID)).isEqualTo(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index b59005aa8dda..2c74d4fa9748 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -17,6 +17,7 @@ import static org.mockito.Mockito.when;
import android.app.AlertDialog;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
@@ -718,6 +719,26 @@ public class InternetDialogTest extends SysuiTestCase {
assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT - 2);
}
+ @Test
+ public void updateDialog_shareWifiIntentNull_hideButton() {
+ when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
+ .thenReturn(null);
+
+ mInternetDialog.updateDialog(false);
+
+ assertThat(mInternetDialog.mShareWifiButton.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void updateDialog_shareWifiShareable_showButton() {
+ when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
+ .thenReturn(new Intent());
+
+ mInternetDialog.updateDialog(false);
+
+ assertThat(mInternetDialog.mShareWifiButton.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
private void setNetworkVisible(boolean ethernetVisible, boolean mobileDataVisible,
boolean connectedWifiVisible) {
mEthernet.setVisibility(ethernetVisible ? View.VISIBLE : View.GONE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 1edeeffe5217..3cce4232ab7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.shade
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import android.view.KeyEvent
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@ import com.android.systemui.dock.DockManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -118,8 +120,10 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
+ @Mock lateinit var keyEventInteractor: KeyEventInteractor
private val notificationExpansionRepository = NotificationExpansionRepository()
+ private lateinit var fakeClock: FakeSystemClock
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler
@@ -148,6 +152,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
testScope = TestScope()
+ fakeClock = FakeSystemClock()
underTest =
NotificationShadeWindowViewController(
lockscreenShadeTransitionController,
@@ -180,7 +185,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
primaryBouncerToGoneTransitionViewModel,
notificationExpansionRepository,
featureFlags,
- FakeSystemClock(),
+ fakeClock,
BouncerMessageInteractor(
FakeBouncerMessageRepository(),
mock(BouncerMessageFactory::class.java),
@@ -188,7 +193,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
CountDownTimerUtil(),
featureFlags
),
- BouncerLogger(logcatLogBuffer("BouncerLog"))
+ BouncerLogger(logcatLogBuffer("BouncerLog")),
+ keyEventInteractor,
)
underTest.setupExpandedStatusBar()
@@ -328,6 +334,33 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
}
@Test
+ fun handleDispatchTouchEvent_launchAnimationRunningTimesOut() =
+ testScope.runTest {
+ // GIVEN touch dispatcher in a state that returns true
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+ whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(
+ true
+ )
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
+
+ // WHEN launch animation is running for 2 seconds
+ fakeClock.setUptimeMillis(10000)
+ underTest.setExpandAnimationRunning(true)
+ fakeClock.advanceTime(2000)
+
+ // THEN touch is ignored
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isFalse()
+
+ // WHEN Launch animation is running for 6 seconds
+ fakeClock.advanceTime(4000)
+
+ // THEN move is ignored, down is handled, and window is notified
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(MOVE_EVENT)).isFalse()
+ assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
+ verify(notificationShadeWindowController).setLaunchingActivity(false)
+ }
+
+ @Test
fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() {
// down event should be intercepted by keyguardViewManager
whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
@@ -345,8 +378,30 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
}
+ @Test
+ fun forwardsDispatchKeyEvent() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+ interactionEventHandler.dispatchKeyEvent(keyEvent)
+ verify(keyEventInteractor).dispatchKeyEvent(keyEvent)
+ }
+
+ @Test
+ fun forwardsDispatchKeyEventPreIme() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+ interactionEventHandler.dispatchKeyEventPreIme(keyEvent)
+ verify(keyEventInteractor).dispatchKeyEventPreIme(keyEvent)
+ }
+
+ @Test
+ fun forwardsInterceptMediaKey() {
+ val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
+ interactionEventHandler.interceptMediaKey(keyEvent)
+ verify(keyEventInteractor).interceptMediaKey(keyEvent)
+ }
+
companion object {
private val DOWN_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
private const val VIEW_BOTTOM = 100
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 829184c4f05a..66d48d64b3a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -38,6 +38,7 @@ import com.android.systemui.dock.DockManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
@@ -198,7 +199,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
CountDownTimerUtil(),
featureFlags
),
- BouncerLogger(logcatLogBuffer("BouncerLog"))
+ BouncerLogger(logcatLogBuffer("BouncerLog")),
+ Mockito.mock(KeyEventInteractor::class.java),
)
controller.setupExpandedStatusBar()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 31bfa3fdf8cb..5fa6b3a15d35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.doAnswer;
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.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -50,6 +51,12 @@ import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import com.android.systemui.utils.os.FakeHandler;
@@ -61,6 +68,10 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -95,6 +106,18 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
private TestableLooper mTestableLooper;
@Mock
private ShadeCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+ @Mock
+ private MobileUiAdapter mMobileUiAdapter;
+ @Mock
+ private MobileIconsViewModel mMobileIconsViewModel;
+ @Mock
+ private ShadeCarrierGroupMobileIconViewModel mShadeCarrierGroupMobileIconViewModel;
+ @Mock
+ private MobileViewLogger mMobileViewLogger;
+ @Mock
+ private MobileContextProvider mMobileContextProvider;
+ @Mock
+ private StatusBarPipelineFlags mStatusBarPipelineFlags;
private FakeSlotIndexResolver mSlotIndexResolver;
private ClickListenerTextView mNoCarrierTextView;
@@ -133,16 +156,35 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
mSlotIndexResolver = new FakeSlotIndexResolver();
+ when(mMobileUiAdapter.getMobileIconsViewModel()).thenReturn(mMobileIconsViewModel);
+
mShadeCarrierGroupController = new ShadeCarrierGroupController.Builder(
- mActivityStarter, handler, TestableLooper.get(this).getLooper(),
- mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker,
- mSlotIndexResolver)
+ mActivityStarter,
+ handler,
+ TestableLooper.get(this).getLooper(),
+ mNetworkController,
+ mCarrierTextControllerBuilder,
+ mContext,
+ mCarrierConfigTracker,
+ mSlotIndexResolver,
+ mMobileUiAdapter,
+ mMobileContextProvider,
+ mStatusBarPipelineFlags
+ )
.setShadeCarrierGroup(mShadeCarrierGroup)
.build();
mShadeCarrierGroupController.setListening(true);
}
+ private void setupWithNewPipeline() {
+ when(mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()).thenReturn(true);
+ when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext);
+ when(mMobileIconsViewModel.getLogger()).thenReturn(mMobileViewLogger);
+ when(mMobileIconsViewModel.viewModelForSub(anyInt(), any()))
+ .thenReturn(mShadeCarrierGroupMobileIconViewModel);
+ }
+
@Test
public void testInitiallyMultiCarrier() {
assertFalse(mShadeCarrierGroupController.isSingleCarrier());
@@ -406,6 +448,129 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
}
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testUpdateModernMobileIcons_addSubscription() {
+ setupWithNewPipeline();
+
+ mShadeCarrier1.setVisibility(View.GONE);
+ mShadeCarrier2.setVisibility(View.GONE);
+ mShadeCarrier3.setVisibility(View.GONE);
+
+ List<Integer> subIds = new ArrayList<>();
+ subIds.add(0);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2, never()).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+
+ resetShadeCarriers();
+
+ subIds.add(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1, times(1)).removeModernMobileView();
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testUpdateModernMobileIcons_removeSubscription() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = new ArrayList<>();
+ subIds.add(0);
+ subIds.add(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+
+ resetShadeCarriers();
+
+ subIds.remove(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1, times(1)).removeModernMobileView();
+ verify(mShadeCarrier2, times(1)).removeModernMobileView();
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2, never()).addModernMobileView(any());
+ verify(mShadeCarrier3, never()).addModernMobileView(any());
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testUpdateModernMobileIcons_removeSubscriptionOutOfOrder() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = new ArrayList<>();
+ subIds.add(0);
+ subIds.add(1);
+ subIds.add(2);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2).addModernMobileView(any());
+ verify(mShadeCarrier3).addModernMobileView(any());
+
+ resetShadeCarriers();
+
+ subIds.remove(1);
+ mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+ verify(mShadeCarrier1).removeModernMobileView();
+ verify(mShadeCarrier2).removeModernMobileView();
+ verify(mShadeCarrier3).removeModernMobileView();
+
+ verify(mShadeCarrier1).addModernMobileView(any());
+ verify(mShadeCarrier2, never()).addModernMobileView(any());
+ verify(mShadeCarrier3).addModernMobileView(any());
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testProcessSubIdList_moreSubsThanSimSlots_listLimitedToMax() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = Arrays.asList(0, 1, 2, 2);
+
+ assertThat(mShadeCarrierGroupController.processSubIdList(subIds).size()).isEqualTo(3);
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testProcessSubIdList_invalidSimSlotIndexFilteredOut() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = Arrays.asList(0, 1, -1);
+
+ List<ShadeCarrierGroupController.IconData> processedSubs =
+ mShadeCarrierGroupController.processSubIdList(subIds);
+ assertThat(processedSubs).hasSize(2);
+ assertThat(processedSubs.get(0).subId).isNotEqualTo(-1);
+ assertThat(processedSubs.get(1).subId).isNotEqualTo(-1);
+ }
+
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @Test
+ public void testProcessSubIdList_indexGreaterThanSimSlotsFilteredOut() {
+ setupWithNewPipeline();
+
+ List<Integer> subIds = Arrays.asList(0, 4);
+
+ List<ShadeCarrierGroupController.IconData> processedSubs =
+ mShadeCarrierGroupController.processSubIdList(subIds);
+ assertThat(processedSubs).hasSize(1);
+ assertThat(processedSubs.get(0).subId).isNotEqualTo(4);
+ }
+
+
@Test
public void testOnlyInternalViewsHaveClickableListener() {
ArgumentCaptor<View.OnClickListener> captor =
@@ -447,6 +612,12 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
.isEqualTo(Settings.ACTION_WIRELESS_SETTINGS);
}
+ private void resetShadeCarriers() {
+ reset(mShadeCarrier1);
+ reset(mShadeCarrier2);
+ reset(mShadeCarrier3);
+ }
+
private class FakeSlotIndexResolver implements ShadeCarrierGroupController.SlotIndexResolver {
public boolean overrideInvalid;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 0b31523e9b98..4c3c3f9d8da5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar.phone
+import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
+import android.app.StatusBarManager.WINDOW_STATE_HIDING
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.ViewTreeObserver
@@ -31,12 +35,15 @@ import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.ShadeControllerImpl
import com.android.systemui.shade.ShadeLogger
import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
@@ -75,6 +82,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@Mock
private lateinit var centralSurfacesImpl: CentralSurfacesImpl
@Mock
+ private lateinit var commandQueue: CommandQueue
+ @Mock
private lateinit var shadeControllerImpl: ShadeControllerImpl
@Mock
private lateinit var windowRootView: Provider<WindowRootView>
@@ -82,6 +91,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
private lateinit var shadeLogger: ShadeLogger
@Mock
private lateinit var viewUtil: ViewUtil
+ private lateinit var statusBarWindowStateController: StatusBarWindowStateController
private lateinit var view: PhoneStatusBarView
private lateinit var controller: PhoneStatusBarViewController
@@ -91,6 +101,9 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+
+ statusBarWindowStateController = StatusBarWindowStateController(DISPLAY_ID, commandQueue)
+
`when`(sysuiUnfoldComponent.getStatusBarMoveFromCenterAnimationController())
.thenReturn(moveFromCenterAnimation)
// create the view and controller on main thread as it requires main looper
@@ -186,6 +199,42 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
verify(shadeViewController, never()).handleExternalTouch(any())
}
+ @Test
+ fun onTouch_windowHidden_centralSurfacesNotNotified() {
+ val callback = getCommandQueueCallback()
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_HIDDEN)
+
+ controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+
+ verify(centralSurfacesImpl, never()).setInteracting(any(), any())
+ }
+
+ @Test
+ fun onTouch_windowHiding_centralSurfacesNotNotified() {
+ val callback = getCommandQueueCallback()
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_HIDING)
+
+ controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+
+ verify(centralSurfacesImpl, never()).setInteracting(any(), any())
+ }
+
+ @Test
+ fun onTouch_windowShowing_centralSurfacesNotified() {
+ val callback = getCommandQueueCallback()
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+
+ controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+
+ verify(centralSurfacesImpl).setInteracting(any(), any())
+ }
+
+ private fun getCommandQueueCallback(): CommandQueue.Callbacks {
+ val captor = argumentCaptor<CommandQueue.Callbacks>()
+ verify(commandQueue).addCallback(captor.capture())
+ return captor.value!!
+ }
+
private fun createViewMock(): PhoneStatusBarView {
val view = spy(view)
val viewTreeObserver = mock(ViewTreeObserver::class.java)
@@ -201,6 +250,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
featureFlags,
userChipViewModel,
centralSurfacesImpl,
+ statusBarWindowStateController,
shadeControllerImpl,
shadeViewController,
windowRootView,
@@ -218,4 +268,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
override var isHingeAngleEnabled: Boolean = false
override val halfFoldedTimeoutMillis: Int = 0
}
+
+ private companion object {
+ const val DISPLAY_ID = 1
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0dc1d9a4b177..6b3bd22d5e62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1802,6 +1802,15 @@ public class ScrimControllerTest extends SysuiTestCase {
assertFalse(ScrimState.UNLOCKED.mAnimateChange);
}
+ @Test
+ public void testNotifScrimAlpha_1f_afterUnlockFinishedAndExpanded() {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ when(mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(true);
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.onUnlockAnimationFinished();
+ assertAlphaAfterExpansion(mNotificationsScrim, 1f, 1f);
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index 50ee6a31d389..ff2875355a6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -52,12 +52,19 @@ class FakeMobileConnectionRepository(
override val cdmaRoaming = MutableStateFlow(false)
- override val networkName =
- MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
+ override val networkName: MutableStateFlow<NetworkNameModel> =
+ MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
+
+ override val carrierName: MutableStateFlow<NetworkNameModel> =
+ MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
+
+ companion object {
+ const val DEFAULT_NETWORK_NAME = "default name"
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 3591c1740329..99e4030e1192 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -75,7 +75,11 @@ class FakeMobileConnectionsRepository(
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
return subIdRepos[subId]
- ?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
+ ?: FakeMobileConnectionRepository(
+ subId,
+ tableLogBuffer,
+ )
+ .also { subIdRepos[subId] = it }
}
override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 5a887ebcee80..d005972043d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -243,13 +243,29 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
private val IMMEDIATE = Dispatchers.Main.immediate
private const val SUB_1_ID = 1
+ private const val SUB_1_NAME = "Carrier $SUB_1_ID"
private val SUB_1 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
- private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+ whenever(it.carrierName).thenReturn(SUB_1_NAME)
+ }
+ private val MODEL_1 =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = SUB_1_NAME,
+ )
private const val SUB_2_ID = 2
+ private const val SUB_2_NAME = "Carrier $SUB_2_ID"
private val SUB_2 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
- private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+ whenever(it.carrierName).thenReturn(SUB_2_NAME)
+ }
+ private val MODEL_2 =
+ SubscriptionModel(
+ subscriptionId = SUB_2_ID,
+ carrierName = SUB_2_NAME,
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index 7573b28c8a7f..57f97ec66a00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -38,7 +38,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -140,6 +139,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
+ launch { conn.carrierName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
@@ -163,6 +163,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
+ assertThat(conn.carrierName.value)
+ .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
// TODO(b/261029387): check these once we start handling them
assertThat(conn.isEmergencyOnly.value).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index efaf15235b46..2712b70a9745 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -546,6 +546,7 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
+ launch { conn.carrierName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
@@ -571,6 +572,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
+ assertThat(conn.carrierName.value)
+ .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
// TODO(b/261029387) check these once we start handling them
assertThat(conn.isEmergencyOnly.value).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 3dd2eaff7bce..9c0cb17700a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
@@ -43,6 +44,7 @@ import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -79,28 +81,51 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
+ private val subscriptionModel =
+ MutableStateFlow(
+ SubscriptionModel(
+ subscriptionId = SUB_ID,
+ carrierName = DEFAULT_NAME,
+ )
+ )
+
private lateinit var mobileRepo: FakeMobileConnectionRepository
private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
@Before
fun setUp() {
- mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
+ mobileRepo =
+ FakeMobileConnectionRepository(
+ SUB_ID,
+ tableLogBuffer,
+ )
carrierMergedRepo =
- FakeMobileConnectionRepository(SUB_ID, tableLogBuffer).apply {
- // Mimicks the real carrier merged repository
- this.isAllowedDuringAirplaneMode.value = true
- }
+ FakeMobileConnectionRepository(
+ SUB_ID,
+ tableLogBuffer,
+ )
+ .apply {
+ // Mimicks the real carrier merged repository
+ this.isAllowedDuringAirplaneMode.value = true
+ }
whenever(
mobileFactory.build(
eq(SUB_ID),
any(),
- eq(DEFAULT_NAME),
+ any(),
+ eq(DEFAULT_NAME_MODEL),
eq(SEP),
)
)
.thenReturn(mobileRepo)
- whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(carrierMergedRepo)
+ whenever(
+ carrierMergedFactory.build(
+ eq(SUB_ID),
+ any(),
+ )
+ )
+ .thenReturn(carrierMergedRepo)
}
@Test
@@ -120,7 +145,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
.build(
SUB_ID,
tableLogBuffer,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
}
@@ -138,7 +164,11 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
assertThat(underTest.operatorAlphaShort.value).isEqualTo(nonCarrierMergedName)
- verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer)
+ verify(carrierMergedFactory, never())
+ .build(
+ SUB_ID,
+ tableLogBuffer,
+ )
}
@Test
@@ -348,7 +378,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -356,7 +387,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -388,7 +420,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -397,7 +430,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = true,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
)
@@ -623,7 +657,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
SUB_ID,
startingIsCarrierMerged,
tableLogBuffer,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
testScope.backgroundScope,
mobileFactory,
@@ -639,8 +674,9 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
val realRepo =
MobileConnectionRepositoryImpl(
SUB_ID,
- defaultNetworkName = NetworkNameModel.Default("default"),
- networkNameSeparator = SEP,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
+ SEP,
telephonyManager,
systemUiCarrierConfig = mock(),
fakeBroadcastDispatcher,
@@ -654,7 +690,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
mobileFactory.build(
eq(SUB_ID),
any(),
- eq(DEFAULT_NAME),
+ any(),
+ eq(DEFAULT_NAME_MODEL),
eq(SEP),
)
)
@@ -677,7 +714,13 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
testScope.backgroundScope,
wifiRepository,
)
- whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(realRepo)
+ whenever(
+ carrierMergedFactory.build(
+ eq(SUB_ID),
+ any(),
+ )
+ )
+ .thenReturn(realRepo)
return realRepo
}
@@ -690,7 +733,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
private companion object {
const val SUB_ID = 42
- private val DEFAULT_NAME = NetworkNameModel.Default("default name")
+ private val DEFAULT_NAME = "default name"
+ private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
private const val SEP = "-"
private const val BUFFER_SEPARATOR = "|"
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 1ff737bfc137..e50e5e31a786 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -62,6 +62,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetwork
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
@@ -78,6 +79,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -109,6 +111,14 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
+ private val subscriptionModel: MutableStateFlow<SubscriptionModel?> =
+ MutableStateFlow(
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = DEFAULT_NAME,
+ )
+ )
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -119,7 +129,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
underTest =
MobileConnectionRepositoryImpl(
SUB_1_ID,
- DEFAULT_NAME,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
SEP,
telephonyManager,
systemUiCarrierConfig,
@@ -179,6 +190,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
// gsmLevel updates, no change to cdmaLevel
strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+ callback.onSignalStrengthsChanged(strength)
assertThat(latest).isEqualTo(2)
@@ -638,12 +650,51 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
}
@Test
+ fun networkNameForSubId_updates() =
+ testScope.runTest {
+ var latest: NetworkNameModel? = null
+ val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+ subscriptionModel.value =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = DEFAULT_NAME,
+ )
+
+ assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+ val updatedName = "Derived Carrier"
+ subscriptionModel.value =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = updatedName,
+ )
+
+ assertThat(latest?.name).isEqualTo(updatedName)
+
+ job.cancel()
+ }
+
+ @Test
+ fun networkNameForSubId_defaultWhenSubscriptionModelNull() =
+ testScope.runTest {
+ var latest: NetworkNameModel? = null
+ val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+ subscriptionModel.value = null
+
+ assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+ job.cancel()
+ }
+
+ @Test
fun networkName_default() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
- assertThat(latest).isEqualTo(DEFAULT_NAME)
+ assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
job.cancel()
}
@@ -701,7 +752,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intentWithoutInfo)
- assertThat(latest).isEqualTo(DEFAULT_NAME)
+ assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
job.cancel()
}
@@ -852,8 +903,9 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
companion object {
private const val SUB_1_ID = 1
- private val DEFAULT_NAME = NetworkNameModel.Default("default name")
- private const val SEP = "-"
+ private val DEFAULT_NAME = "Fake Mobile Network"
+ private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+ private val SEP = "-"
private const val SPN = "testSpn"
private const val PLMN = "testPlmn"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index 4f15aed00230..ea60aa74f12b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -36,6 +36,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
@@ -47,6 +48,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -97,6 +99,7 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
+ @Mock private lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
private val mobileMappings = FakeMobileMappingsProxy()
private val systemUiCarrierConfig =
@@ -113,11 +116,16 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
- connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
+ connectionsRepo =
+ FakeMobileConnectionsRepository(
+ mobileMappings,
+ tableLogger,
+ )
underTest =
MobileConnectionRepositoryImpl(
SUB_1_ID,
+ subscriptionModel,
DEFAULT_NAME,
SEP,
telephonyManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index c8b6f13d6902..fd05cc495692 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -1190,30 +1190,36 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
companion object {
// Subscription 1
private const val SUB_1_ID = 1
+ private const val SUB_1_NAME = "Carrier $SUB_1_ID"
private val GROUP_1 = ParcelUuid(UUID.randomUUID())
private val SUB_1 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
whenever(it.groupUuid).thenReturn(GROUP_1)
+ whenever(it.carrierName).thenReturn(SUB_1_NAME)
}
private val MODEL_1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
groupUuid = GROUP_1,
+ carrierName = SUB_1_NAME,
)
// Subscription 2
private const val SUB_2_ID = 2
+ private const val SUB_2_NAME = "Carrier $SUB_2_ID"
private val GROUP_2 = ParcelUuid(UUID.randomUUID())
private val SUB_2 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
whenever(it.groupUuid).thenReturn(GROUP_2)
+ whenever(it.carrierName).thenReturn(SUB_2_NAME)
}
private val MODEL_2 =
SubscriptionModel(
subscriptionId = SUB_2_ID,
groupUuid = GROUP_2,
+ carrierName = SUB_2_NAME,
)
// Subs 3 and 4 are considered to be in the same group ------------------------------------
@@ -1242,9 +1248,14 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
// Carrier merged subscription
private const val SUB_CM_ID = 5
+ private const val SUB_CM_NAME = "Carrier $SUB_CM_ID"
private val SUB_CM =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
- private val MODEL_CM = SubscriptionModel(subscriptionId = SUB_CM_ID)
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
+ whenever(it.carrierName).thenReturn(SUB_CM_NAME)
+ }
+ private val MODEL_CM =
+ SubscriptionModel(subscriptionId = SUB_CM_ID, carrierName = SUB_CM_NAME)
private val WIFI_INFO_CM =
mock<WifiInfo>().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index 8d1da69d6877..a3df785c5dae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -44,6 +44,8 @@ class FakeMobileIconInteractor(
override val mobileIsDefault = MutableStateFlow(true)
+ override val isSingleCarrier = MutableStateFlow(true)
+
override val networkTypeIconGroup =
MutableStateFlow<NetworkTypeIconModel>(
NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
@@ -51,6 +53,8 @@ class FakeMobileIconInteractor(
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo mode"))
+ override val carrierName = MutableStateFlow("demo mode")
+
private val _isEmergencyOnly = MutableStateFlow(false)
override val isEmergencyOnly = _isEmergencyOnly
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index b2bbcfd3d6ef..82b7ec41d148 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -64,6 +64,8 @@ class FakeMobileIconsInteractor(
override val mobileIsDefault = MutableStateFlow(false)
+ override val isSingleCarrier = MutableStateFlow(true)
+
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 58d3804b7155..e3c59adef529 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
@@ -40,6 +41,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -56,6 +58,15 @@ class MobileIconInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconInteractor
private val mobileMappingsProxy = FakeMobileMappingsProxy()
private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
+
+ private val subscriptionModel =
+ MutableStateFlow(
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ carrierName = DEFAULT_NAME,
+ )
+ )
+
private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID, mock())
private val testDispatcher = UnconfinedTestDispatcher()
@@ -432,7 +443,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
}
@Test
- fun networkName_usesOperatorAlphaShotWhenNonNullAndRepoIsDefault() =
+ fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
@@ -440,7 +451,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
val testOperatorName = "operatorAlphaShort"
// Default network name, operator name is non-null, uses the operator name
- connectionRepository.networkName.value = DEFAULT_NAME
+ connectionRepository.networkName.value = DEFAULT_NAME_MODEL
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
@@ -448,10 +459,39 @@ class MobileIconInteractorTest : SysuiTestCase() {
// Default network name, operator name is null, uses the default
connectionRepository.operatorAlphaShort.value = null
+ assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+ // Derived network name, operator name non-null, uses the derived name
+ connectionRepository.networkName.value = DERIVED_NAME_MODEL
+ connectionRepository.operatorAlphaShort.value = testOperatorName
+
+ assertThat(latest).isEqualTo(DERIVED_NAME_MODEL)
+
+ job.cancel()
+ }
+
+ @Test
+ fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
+ testScope.runTest {
+ var latest: String? = null
+ val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+ val testOperatorName = "operatorAlphaShort"
+
+ // Default network name, operator name is non-null, uses the operator name
+ connectionRepository.carrierName.value = DEFAULT_NAME_MODEL
+ connectionRepository.operatorAlphaShort.value = testOperatorName
+
+ assertThat(latest).isEqualTo(testOperatorName)
+
+ // Default network name, operator name is null, uses the default
+ connectionRepository.operatorAlphaShort.value = null
+
assertThat(latest).isEqualTo(DEFAULT_NAME)
// Derived network name, operator name non-null, uses the derived name
- connectionRepository.networkName.value = DERIVED_NAME
+ connectionRepository.carrierName.value =
+ NetworkNameModel.SubscriptionDerived(DERIVED_NAME)
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(DERIVED_NAME)
@@ -460,6 +500,21 @@ class MobileIconInteractorTest : SysuiTestCase() {
}
@Test
+ fun isSingleCarrier_matchesParent() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ mobileIconsInteractor.isSingleCarrier.value = true
+ assertThat(latest).isTrue()
+
+ mobileIconsInteractor.isSingleCarrier.value = false
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun isForceHidden_matchesParent() =
testScope.runTest {
var latest: Boolean? = null
@@ -494,6 +549,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
mobileIconsInteractor.activeDataConnectionHasDataEnabled,
mobileIconsInteractor.alwaysShowDataRatIcon,
mobileIconsInteractor.alwaysUseCdmaLevel,
+ mobileIconsInteractor.isSingleCarrier,
mobileIconsInteractor.mobileIsDefault,
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
@@ -510,7 +566,9 @@ class MobileIconInteractorTest : SysuiTestCase() {
private const val SUB_1_ID = 1
- private val DEFAULT_NAME = NetworkNameModel.Default("test default name")
- private val DERIVED_NAME = NetworkNameModel.IntentDerived("test derived name")
+ private val DEFAULT_NAME = "test default name"
+ private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+ private val DERIVED_NAME = "test derived name"
+ private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 1fb76b048d47..3e6f90931b87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -527,6 +527,57 @@ class MobileIconsInteractorTest : SysuiTestCase() {
}
@Test
+ fun isSingleCarrier_zeroSubscriptions_false() =
+ testScope.runTest {
+ var latest: Boolean? = true
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(emptyList())
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isSingleCarrier_oneSubscription_true() =
+ testScope.runTest {
+ var latest: Boolean? = false
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1))
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isSingleCarrier_twoSubscriptions_false() =
+ testScope.runTest {
+ var latest: Boolean? = true
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isSingleCarrier_updates() =
+ testScope.runTest {
+ var latest: Boolean? = false
+ val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1))
+ assertThat(latest).isTrue()
+
+ connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
testScope.runTest {
var latest: Boolean? = null
@@ -745,6 +796,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = subscriptionIds.first,
isOpportunistic = opportunistic.first,
groupUuid = groupUuid,
+ carrierName = "Carrier ${subscriptionIds.first}"
)
val sub2 =
@@ -752,6 +804,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = subscriptionIds.second,
isOpportunistic = opportunistic.second,
groupUuid = groupUuid,
+ carrierName = "Carrier ${opportunistic.second}"
)
return Pair(sub1, sub2)
@@ -760,11 +813,13 @@ class MobileIconsInteractorTest : SysuiTestCase() {
companion object {
private const val SUB_1_ID = 1
- private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+ private val SUB_1 =
+ SubscriptionModel(subscriptionId = SUB_1_ID, carrierName = "Carrier $SUB_1_ID")
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
private const val SUB_2_ID = 2
- private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+ private val SUB_2 =
+ SubscriptionModel(subscriptionId = SUB_2_ID, carrierName = "Carrier $SUB_2_ID")
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
private const val SUB_3_ID = 3
@@ -773,6 +828,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = SUB_3_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
+ carrierName = "Carrier $SUB_3_ID"
)
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
@@ -782,6 +838,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = SUB_4_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
+ carrierName = "Carrier $SUB_4_ID"
)
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index f0458fa83d38..065dfbabf051 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -92,15 +92,31 @@ class MobileIconsViewModelTest : SysuiTestCase() {
interactor.filteredSubscriptions.value =
listOf(
- SubscriptionModel(subscriptionId = 1, isOpportunistic = false),
+ SubscriptionModel(
+ subscriptionId = 1,
+ isOpportunistic = false,
+ carrierName = "Carrier 1",
+ ),
)
assertThat(latest).isEqualTo(listOf(1))
interactor.filteredSubscriptions.value =
listOf(
- SubscriptionModel(subscriptionId = 2, isOpportunistic = false),
- SubscriptionModel(subscriptionId = 5, isOpportunistic = true),
- SubscriptionModel(subscriptionId = 7, isOpportunistic = true),
+ SubscriptionModel(
+ subscriptionId = 2,
+ isOpportunistic = false,
+ carrierName = "Carrier 2",
+ ),
+ SubscriptionModel(
+ subscriptionId = 5,
+ isOpportunistic = true,
+ carrierName = "Carrier 5",
+ ),
+ SubscriptionModel(
+ subscriptionId = 7,
+ isOpportunistic = true,
+ carrierName = "Carrier 7",
+ ),
)
assertThat(latest).isEqualTo(listOf(2, 5, 7))
@@ -138,6 +154,33 @@ class MobileIconsViewModelTest : SysuiTestCase() {
}
@Test
+ fun caching_mobileIconInteractorIsReusedForSameSubId() =
+ testScope.runTest {
+ val interactor1 = underTest.mobileIconInteractorForSub(1)
+ val interactor2 = underTest.mobileIconInteractorForSub(1)
+
+ assertThat(interactor1).isSameInstanceAs(interactor2)
+ }
+
+ @Test
+ fun caching_invalidInteractorssAreRemovedFromCacheWhenSubDisappears() =
+ testScope.runTest {
+ // Retrieve interactors to trigger caching
+ val interactor1 = underTest.mobileIconInteractorForSub(1)
+ val interactor2 = underTest.mobileIconInteractorForSub(2)
+
+ // Both impls are cached
+ assertThat(underTest.mobileIconInteractorSubIdCache)
+ .containsExactly(1, interactor1, 2, interactor2)
+
+ // SUB_1 is removed from the list...
+ interactor.filteredSubscriptions.value = listOf(SUB_2)
+
+ // ... and dropped from the cache
+ assertThat(underTest.mobileIconInteractorSubIdCache).containsExactly(2, interactor2)
+ }
+
+ @Test
fun firstMobileSubShowingNetworkTypeIcon_noSubs_false() =
testScope.runTest {
var latest: Boolean? = null
@@ -308,8 +351,23 @@ class MobileIconsViewModelTest : SysuiTestCase() {
}
companion object {
- private val SUB_1 = SubscriptionModel(subscriptionId = 1, isOpportunistic = false)
- private val SUB_2 = SubscriptionModel(subscriptionId = 2, isOpportunistic = false)
- private val SUB_3 = SubscriptionModel(subscriptionId = 3, isOpportunistic = false)
+ private val SUB_1 =
+ SubscriptionModel(
+ subscriptionId = 1,
+ isOpportunistic = false,
+ carrierName = "Carrier 1",
+ )
+ private val SUB_2 =
+ SubscriptionModel(
+ subscriptionId = 2,
+ isOpportunistic = false,
+ carrierName = "Carrier 2",
+ )
+ private val SUB_3 =
+ SubscriptionModel(
+ subscriptionId = 3,
+ isOpportunistic = false,
+ carrierName = "Carrier 3",
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
index 85052e600486..e4318659bef9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
@@ -64,7 +64,7 @@ import java.util.List;
public class InflatedSmartRepliesTest extends SysuiTestCase {
private static final Intent TEST_INTENT = new Intent("com.android.SMART_REPLY_VIEW_ACTION");
- private static final Intent WHITELISTED_TEST_INTENT =
+ private static final Intent ALLOWLISTED_TEST_INTENT =
new Intent("com.android.WHITELISTED_TEST_ACTION");
@Mock private SmartReplyConstants mSmartReplyConstants;
@@ -343,7 +343,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
assertThat(smartReplyState.getSmartReplies().choices)
.containsExactlyElementsIn(mEntry.getSmartReplies()).inOrder();
- // Since no apps are whitelisted no actions should be shown.
+ // Since no apps are allowlisted no actions should be shown.
assertThat(smartReplyState.getSmartActions().actions).isEmpty();
assertThat(smartReplyState.getSuppressedActions()).isNull();
assertThat(smartReplyState.getHasPhishingAction()).isFalse();
@@ -358,7 +358,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
allowedResolveInfo.activityInfo.packageName = allowedPackage;
when(mPackageManagerWrapper
.resolveActivity(
- argThat(intent -> WHITELISTED_TEST_INTENT.getAction().equals(
+ argThat(intent -> ALLOWLISTED_TEST_INTENT.getAction().equals(
intent.getAction())),
anyInt() /* flags */))
.thenReturn(allowedResolveInfo);
@@ -368,7 +368,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
// suggestions.
setupAppGeneratedReplies(null /* smartReplies */);
ArrayList<Notification.Action> actions = new ArrayList<>();
- actions.add(createAction("allowed action", WHITELISTED_TEST_INTENT));
+ actions.add(createAction("allowed action", ALLOWLISTED_TEST_INTENT));
actions.add(createAction("non-allowed action", TEST_INTENT));
modifyRanking(mEntry)
@@ -379,7 +379,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
InflatedSmartReplyState smartReplyState =
mSmartReplyStateInflater.chooseSmartRepliesAndActions(mEntry);
- // Only the action for the whitelisted package should be allowed.
+ // Only the action for the allowlisted package should be allowed.
assertThat(smartReplyState.getSmartActions().actions)
.containsExactly(mEntry.getSmartActions().get(0));
assertThat(smartReplyState.getSuppressedActions()).isNull();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 5f0011bc809a..c12df9837a63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -32,7 +32,6 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assume.assumeNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -500,123 +499,45 @@ public class VolumeDialogImplTest extends SysuiTestCase {
@Test
public void ifPortraitHalfOpen_drawVerticallyTop() {
- DevicePostureController devicePostureController = mock(DevicePostureController.class);
- when(devicePostureController.getDevicePosture())
- .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- devicePostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0 , null);
-
- verify(devicePostureController).addCallback(any());
- dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
+ mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
mTestableLooper.processAllMessages(); // let dismiss() finish
setOrientation(Configuration.ORIENTATION_PORTRAIT);
// Call show() to trigger layout updates before verifying position
- dialog.show(SHOW_REASON_UNKNOWN);
+ mDialog.show(SHOW_REASON_UNKNOWN);
mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
- int gravity = dialog.getWindowGravity();
+ int gravity = mDialog.getWindowGravity();
assertEquals(Gravity.TOP, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
- cleanUp(dialog);
}
@Test
public void ifPortraitAndOpen_drawCenterVertically() {
- DevicePostureController devicePostureController = mock(DevicePostureController.class);
- when(devicePostureController.getDevicePosture())
- .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- devicePostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0, null);
-
- verify(devicePostureController).addCallback(any());
- dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED);
+ mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED);
mTestableLooper.processAllMessages(); // let dismiss() finish
setOrientation(Configuration.ORIENTATION_PORTRAIT);
- dialog.show(SHOW_REASON_UNKNOWN);
+ mDialog.show(SHOW_REASON_UNKNOWN);
mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
- int gravity = dialog.getWindowGravity();
+ int gravity = mDialog.getWindowGravity();
assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
- cleanUp(dialog);
}
@Test
public void ifLandscapeAndHalfOpen_drawCenterVertically() {
- DevicePostureController devicePostureController = mock(DevicePostureController.class);
- when(devicePostureController.getDevicePosture())
- .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- devicePostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0, null);
-
- verify(devicePostureController).addCallback(any());
- dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
+ mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
mTestableLooper.processAllMessages(); // let dismiss() finish
setOrientation(Configuration.ORIENTATION_LANDSCAPE);
- dialog.show(SHOW_REASON_UNKNOWN);
+ mDialog.show(SHOW_REASON_UNKNOWN);
mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
- int gravity = dialog.getWindowGravity();
+ int gravity = mDialog.getWindowGravity();
assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
- cleanUp(dialog);
}
@Test
@@ -627,31 +548,9 @@ public class VolumeDialogImplTest extends SysuiTestCase {
@Test
public void dialogDestroy_removesPostureControllerCallback() {
- VolumeDialogImpl dialog = new VolumeDialogImpl(
- getContext(),
- mVolumeDialogController,
- mAccessibilityMgr,
- mDeviceProvisionedController,
- mConfigurationController,
- mMediaOutputDialogFactory,
- mVolumePanelFactory,
- mActivityStarter,
- mInteractionJankMonitor,
- false,
- mCsdWarningDialogFactory,
- mPostureController,
- mTestableLooper.getLooper(),
- mDumpManager,
- mFeatureFlags
- );
- dialog.init(0, null);
-
verify(mPostureController, never()).removeCallback(any());
- dialog.destroy();
-
+ mDialog.destroy();
verify(mPostureController).removeCallback(any());
-
- cleanUp(dialog);
}
private void setOrientation(int orientation) {
@@ -736,6 +635,8 @@ public class VolumeDialogImplTest extends SysuiTestCase {
*/
private void assertRingerContainerDescribesItsState(int ringerMode,
RingerDrawerState drawerState) {
+ assumeHasDrawer();
+
State state = createShellState();
state.ringerModeInternal = ringerMode;
mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
new file mode 100644
index 000000000000..94ed608f4844
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.wmshell
+
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SharedPreferences
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.model.SysUiStateTest
+import com.android.wm.shell.bubbles.Bubble
+import com.android.wm.shell.bubbles.BubbleEducationController
+import com.android.wm.shell.bubbles.PREF_MANAGED_EDUCATION
+import com.android.wm.shell.bubbles.PREF_STACK_EDUCATION
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mockito
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class BubbleEducationControllerTest : SysUiStateTest() {
+ private val sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor::class.java)
+ private val sharedPrefs = Mockito.mock(SharedPreferences::class.java)
+ private val context = Mockito.mock(Context::class.java)
+ private lateinit var sut: BubbleEducationController
+
+ @Before
+ fun setUp() {
+ Mockito.`when`(context.packageName).thenReturn("packageName")
+ Mockito.`when`(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs)
+ Mockito.`when`(context.contentResolver)
+ .thenReturn(Mockito.mock(ContentResolver::class.java))
+ Mockito.`when`(sharedPrefs.edit()).thenReturn(sharedPrefsEditor)
+ sut = BubbleEducationController(context)
+ }
+
+ @Test
+ fun testSeenStackEducation_read() {
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.hasSeenStackEducation, true)
+ Mockito.verify(sharedPrefs).getBoolean(PREF_STACK_EDUCATION, false)
+ }
+
+ @Test
+ fun testSeenStackEducation_write() {
+ sut.hasSeenStackEducation = true
+ Mockito.verify(sharedPrefsEditor).putBoolean(PREF_STACK_EDUCATION, true)
+ }
+
+ @Test
+ fun testSeenManageEducation_read() {
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.hasSeenManageEducation, true)
+ Mockito.verify(sharedPrefs).getBoolean(PREF_MANAGED_EDUCATION, false)
+ }
+
+ @Test
+ fun testSeenManageEducation_write() {
+ sut.hasSeenManageEducation = true
+ Mockito.verify(sharedPrefsEditor).putBoolean(PREF_MANAGED_EDUCATION, true)
+ }
+
+ @Test
+ fun testShouldShowStackEducation() {
+ val bubble = Mockito.mock(Bubble::class.java)
+ // When bubble is null
+ assertEquals(sut.shouldShowStackEducation(null), false)
+ // When bubble is not conversation
+ Mockito.`when`(bubble.isConversation).thenReturn(false)
+ assertEquals(sut.shouldShowStackEducation(bubble), false)
+ // When bubble is conversation and has seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.shouldShowStackEducation(bubble), false)
+ // When bubble is conversation and has not seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+ assertEquals(sut.shouldShowStackEducation(bubble), true)
+ }
+
+ @Test
+ fun testShouldShowManageEducation() {
+ val bubble = Mockito.mock(Bubble::class.java)
+ // When bubble is null
+ assertEquals(sut.shouldShowManageEducation(null), false)
+ // When bubble is not conversation
+ Mockito.`when`(bubble.isConversation).thenReturn(false)
+ assertEquals(sut.shouldShowManageEducation(bubble), false)
+ // When bubble is conversation and has seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ assertEquals(sut.shouldShowManageEducation(bubble), false)
+ // When bubble is conversation and has not seen stack edu
+ Mockito.`when`(bubble.isConversation).thenReturn(true)
+ Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+ assertEquals(sut.shouldShowManageEducation(bubble), true)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
index 013dbb458c22..43c9c99744c5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
@@ -18,7 +18,17 @@ package com.android.systemui.flags
import java.io.PrintWriter
-class FakeFeatureFlags : FeatureFlags {
+class FakeFeatureFlagsClassic : FakeFeatureFlags()
+
+@Deprecated(
+ message = "Use FakeFeatureFlagsClassic instead.",
+ replaceWith =
+ ReplaceWith(
+ "FakeFeatureFlagsClassic",
+ "com.android.systemui.flags.FakeFeatureFlagsClassic",
+ ),
+)
+open class FakeFeatureFlags : FeatureFlagsClassic {
private val booleanFlags = mutableMapOf<String, Boolean>()
private val stringFlags = mutableMapOf<String, String>()
private val intFlags = mutableMapOf<String, Int>()
@@ -66,12 +76,11 @@ class FakeFeatureFlags : FeatureFlags {
* Set the given flag's default value if no other value has been set.
*
* REMINDER: You should always test your code with your flag in both configurations, so
- * generally you should be setting a particular value. This method should be reserved for
- * situations where the flag needs to be read (e.g. in the class constructor), but its
- * value shouldn't affect the actual test cases. In those cases, it's mildly safer to use
- * this method than to hard-code `false` or `true` because then at least if you're wrong,
- * and the flag value *does* matter, you'll notice when the flag is flipped and tests
- * start failing.
+ * generally you should be setting a particular value. This method should be reserved for
+ * situations where the flag needs to be read (e.g. in the class constructor), but its value
+ * shouldn't affect the actual test cases. In those cases, it's mildly safer to use this method
+ * than to hard-code `false` or `true` because then at least if you're wrong, and the flag value
+ * *does* matter, you'll notice when the flag is flipped and tests start failing.
*/
fun setDefault(flag: BooleanFlag) = booleanFlags.putIfAbsent(flag.name, flag.default)
@@ -79,12 +88,11 @@ class FakeFeatureFlags : FeatureFlags {
* Set the given flag's default value if no other value has been set.
*
* REMINDER: You should always test your code with your flag in both configurations, so
- * generally you should be setting a particular value. This method should be reserved for
- * situations where the flag needs to be read (e.g. in the class constructor), but its
- * value shouldn't affect the actual test cases. In those cases, it's mildly safer to use
- * this method than to hard-code `false` or `true` because then at least if you're wrong,
- * and the flag value *does* matter, you'll notice when the flag is flipped and tests
- * start failing.
+ * generally you should be setting a particular value. This method should be reserved for
+ * situations where the flag needs to be read (e.g. in the class constructor), but its value
+ * shouldn't affect the actual test cases. In those cases, it's mildly safer to use this method
+ * than to hard-code `false` or `true` because then at least if you're wrong, and the flag value
+ * *does* matter, you'll notice when the flag is flipped and tests start failing.
*/
fun setDefault(flag: SysPropBooleanFlag) = booleanFlags.putIfAbsent(flag.name, flag.default)
@@ -123,10 +131,8 @@ class FakeFeatureFlags : FeatureFlags {
}
override fun removeListener(listener: FlagListenable.Listener) {
- listenerflagNames.remove(listener)?.let {
- flagNames -> flagNames.forEach {
- id -> flagListeners[id]?.remove(listener)
- }
+ listenerflagNames.remove(listener)?.let { flagNames ->
+ flagNames.forEach { id -> flagListeners[id]?.remove(listener) }
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 819f8a1eac1d..7e09b5ea9fa5 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3958,14 +3958,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_APPWIDGET, null);
} catch (SecurityException se) {
- if (!isCallerBindAppWidgetWhiteListedLocked(packageName)) {
+ if (!isCallerBindAppWidgetAllowListedLocked(packageName)) {
return false;
}
}
return true;
}
- private boolean isCallerBindAppWidgetWhiteListedLocked(String packageName) {
+ private boolean isCallerBindAppWidgetAllowListedLocked(String packageName) {
final int userId = UserHandle.getCallingUserId();
final int packageUid = getUidForPackage(packageName, userId);
if (packageUid < 0) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 63a607c8d0d4..5b8bdd57ccbb 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1413,7 +1413,7 @@ final class AutofillManagerServiceImpl
Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities="
+ activities + ")");
}
- whitelistForAugmentedAutofillPackages(packages, activities);
+ allowlistForAugmentedAutofillPackages(packages, activities);
final String serviceName;
if (mRemoteAugmentedAutofillServiceInfo != null) {
serviceName = mRemoteAugmentedAutofillServiceInfo.getComponentName()
@@ -1477,7 +1477,7 @@ final class AutofillManagerServiceImpl
/**
* @throws IllegalArgumentException if packages or components are empty.
*/
- private void whitelistForAugmentedAutofillPackages(@Nullable List<String> packages,
+ private void allowlistForAugmentedAutofillPackages(@Nullable List<String> packages,
@Nullable List<ComponentName> components) {
// TODO(b/123100824): add CTS test for when it's null
synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionRendorInfoCallbackOnResultListener.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionRendorInfoCallbackOnResultListener.java
new file mode 100644
index 000000000000..7351ef59feca
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionRendorInfoCallbackOnResultListener.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.util.Slog;
+import android.view.autofill.AutofillId;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+import java.lang.ref.WeakReference;
+import java.util.function.Consumer;
+
+final class InlineSuggestionRendorInfoCallbackOnResultListener implements
+ RemoteCallback.OnResultListener{
+ private static final String TAG = "InlineSuggestionRendorInfoCallbackOnResultListener";
+
+ private final int mRequestIdCopy;
+ private final AutofillId mFocusedId;
+ private final WeakReference<Session> mSessionWeakReference;
+ private final Consumer<InlineSuggestionsRequest> mInlineSuggestionsRequestConsumer;
+
+ InlineSuggestionRendorInfoCallbackOnResultListener(WeakReference<Session> sessionWeakReference,
+ int requestIdCopy,
+ Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer,
+ AutofillId focusedId) {
+ this.mRequestIdCopy = requestIdCopy;
+ this.mInlineSuggestionsRequestConsumer = inlineSuggestionsRequestConsumer;
+ this.mSessionWeakReference = sessionWeakReference;
+ this.mFocusedId = focusedId;
+ }
+ public void onResult(@Nullable Bundle result) {
+ Session session = this.mSessionWeakReference.get();
+ if (session == null) {
+ Slog.wtf(TAG, "Session is null before trying to call onResult");
+ return;
+ }
+ synchronized (session.mLock) {
+ if (session.mDestroyed) {
+ Slog.wtf(TAG, "Session is destroyed before trying to call onResult");
+ return;
+ }
+ session.mInlineSessionController.onCreateInlineSuggestionsRequestLocked(
+ this.mFocusedId,
+ session.inlineSuggestionsRequestCacheDecorator(
+ this.mInlineSuggestionsRequestConsumer, this.mRequestIdCopy),
+ result);
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionRequestConsumer.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionRequestConsumer.java
new file mode 100644
index 000000000000..a3efb25a5735
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionRequestConsumer.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import android.util.Slog;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+import java.lang.ref.WeakReference;
+import java.util.function.Consumer;
+
+class InlineSuggestionRequestConsumer implements Consumer<InlineSuggestionsRequest> {
+
+ static final String TAG = "InlineSuggestionRequestConsumer";
+
+ private final WeakReference<Session.AssistDataReceiverImpl> mAssistDataReceiverWeakReference;
+ private final WeakReference<ViewState> mViewStateWeakReference;
+
+ InlineSuggestionRequestConsumer(WeakReference<Session.AssistDataReceiverImpl>
+ assistDataReceiverWeakReference,
+ WeakReference<ViewState> viewStateWeakReference) {
+ mAssistDataReceiverWeakReference = assistDataReceiverWeakReference;
+ mViewStateWeakReference = viewStateWeakReference;
+ }
+
+ @Override
+ public void accept(InlineSuggestionsRequest inlineSuggestionsRequest) {
+ Session.AssistDataReceiverImpl assistDataReceiver = mAssistDataReceiverWeakReference.get();
+ ViewState viewState = mViewStateWeakReference.get();
+ if (assistDataReceiver == null) {
+ Slog.wtf(TAG, "assistDataReceiver is null when accepting new inline suggestion"
+ + "requests");
+ return;
+ }
+
+ if (viewState == null) {
+ Slog.wtf(TAG, "view state is null when accepting new inline suggestion requests");
+ return;
+ }
+ assistDataReceiver.handleInlineSuggestionRequest(inlineSuggestionsRequest, viewState);
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 1827a5b0a0fb..1ae912544cc8 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -326,7 +326,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* Id of the View currently being displayed.
*/
@GuardedBy("mLock")
- @Nullable private AutofillId mCurrentViewId;
+ private @Nullable AutofillId mCurrentViewId;
@GuardedBy("mLock")
private IAutoFillManagerClient mClient;
@@ -374,7 +374,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private Bundle mClientState;
@GuardedBy("mLock")
- private boolean mDestroyed;
+ boolean mDestroyed;
/**
* Helper used to handle state of Save UI when it must be hiding to show a custom description
@@ -453,7 +453,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private ArrayList<AutofillId> mAugmentedAutofillableIds;
@NonNull
- private final AutofillInlineSessionController mInlineSessionController;
+ final AutofillInlineSessionController mInlineSessionController;
/**
* Receiver of assist data from the app's {@link Activity}.
@@ -623,7 +623,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* TODO(b/151867668): improve how asynchronous data dependencies are handled, without using
* CountDownLatch.
*/
- private final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
+ final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
@GuardedBy("mLock")
private boolean mWaitForInlineRequest;
@GuardedBy("mLock")
@@ -638,18 +638,28 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mPendingFillRequest = null;
mWaitForInlineRequest = isInlineRequest;
mPendingInlineSuggestionsRequest = null;
- return isInlineRequest ? (inlineSuggestionsRequest) -> {
- synchronized (mLock) {
- if (!mWaitForInlineRequest || mPendingInlineSuggestionsRequest != null) {
- return;
- }
- mWaitForInlineRequest = inlineSuggestionsRequest != null;
- mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
- mWaitForInlineRequest = inlineSuggestionsRequest != null;
- maybeRequestFillFromServiceLocked();
- viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
+ if (isInlineRequest) {
+ WeakReference<AssistDataReceiverImpl> assistDataReceiverWeakReference =
+ new WeakReference<AssistDataReceiverImpl>(this);
+ WeakReference<ViewState> viewStateWeakReference =
+ new WeakReference<ViewState>(viewState);
+ return new InlineSuggestionRequestConsumer(assistDataReceiverWeakReference,
+ viewStateWeakReference);
+ }
+ return null;
+ }
+
+ void handleInlineSuggestionRequest(InlineSuggestionsRequest inlineSuggestionsRequest,
+ ViewState viewState) {
+ synchronized (mLock) {
+ if (!mWaitForInlineRequest || mPendingInlineSuggestionsRequest != null) {
+ return;
}
- } : null;
+ mWaitForInlineRequest = inlineSuggestionsRequest != null;
+ mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
+ maybeRequestFillFromServiceLocked();
+ viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
+ }
}
void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
@@ -1276,18 +1286,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
viewState, /* isInlineRequest= */ true);
}
if (inlineSuggestionsRequestConsumer != null) {
- final AutofillId focusedId = mCurrentViewId;
final int requestIdCopy = requestId;
+ final AutofillId focusedId = mCurrentViewId;
+
+ WeakReference sessionWeakReference = new WeakReference<Session>(this);
+ InlineSuggestionRendorInfoCallbackOnResultListener
+ inlineSuggestionRendorInfoCallbackOnResultListener =
+ new InlineSuggestionRendorInfoCallbackOnResultListener(
+ sessionWeakReference,
+ requestIdCopy,
+ inlineSuggestionsRequestConsumer,
+ focusedId);
+ RemoteCallback inlineSuggestionRendorInfoCallback = new RemoteCallback(
+ inlineSuggestionRendorInfoCallbackOnResultListener, mHandler);
+
remoteRenderService.getInlineSuggestionsRendererInfo(
- new RemoteCallback((extras) -> {
- synchronized (mLock) {
- mInlineSessionController.onCreateInlineSuggestionsRequestLocked(
- focusedId, inlineSuggestionsRequestCacheDecorator(
- inlineSuggestionsRequestConsumer, requestIdCopy),
- extras);
- }
- }, mHandler)
- );
+ inlineSuggestionRendorInfoCallback);
viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
} else if (mSessionFlags.mClientSuggestionsEnabled) {
@@ -5554,7 +5568,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
@NonNull
- private Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestCacheDecorator(
+ Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestCacheDecorator(
@NonNull Consumer<InlineSuggestionsRequest> consumer, int requestId) {
return inlineSuggestionsRequest -> {
consumer.accept(inlineSuggestionsRequest);
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index b6baf7e89a5d..b573800fde18 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -133,7 +133,8 @@ import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.utils.BackupEligibilityRules;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupManagerMonitorDumpsysUtils;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.android.server.backup.utils.BackupObserverUtils;
import com.android.server.backup.utils.SparseArrayUtils;
@@ -142,6 +143,7 @@ import dalvik.annotation.optimization.NeverCompile;
import com.google.android.collect.Sets;
import java.io.BufferedInputStream;
+import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -150,6 +152,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
@@ -1834,12 +1837,14 @@ public class UserBackupManagerService {
*/
public int requestBackup(String[] packages, IBackupObserver observer,
IBackupManagerMonitor monitor, int flags) {
+ BackupManagerMonitorEventSender mBackupManagerMonitorEventSender =
+ getBMMEventSender(monitor);
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
if (packages == null || packages.length < 1) {
Slog.e(TAG, addUserIdToLogMessage(mUserId, "No packages named for backup request"));
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
- monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES,
null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
throw new IllegalArgumentException("No packages are provided for backup");
@@ -1857,7 +1862,7 @@ public class UserBackupManagerService {
final int logTag = mSetupComplete
? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED
: BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
- monitor = BackupManagerMonitorUtils.monitorEvent(monitor, logTag, null,
+ mBackupManagerMonitorEventSender.monitorEvent(logTag, null,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
}
@@ -1875,7 +1880,7 @@ public class UserBackupManagerService {
} catch (TransportNotRegisteredException | TransportNotAvailableException
| RemoteException e) {
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
- monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
return BackupManager.ERROR_TRANSPORT_ABORTED;
@@ -3070,7 +3075,9 @@ public class UserBackupManagerService {
/* caller */ "BMS.reportDelayedRestoreResult");
IBackupManagerMonitor monitor = transportClient.getBackupManagerMonitor();
- BackupManagerMonitorUtils.sendAgentLoggingResults(monitor, packageInfo, results,
+ BackupManagerMonitorEventSender mBackupManagerMonitorEventSender =
+ getBMMEventSender(monitor);
+ mBackupManagerMonitorEventSender.sendAgentLoggingResults(packageInfo, results,
BackupAnnotations.OperationType.RESTORE);
} catch (NameNotFoundException | TransportNotAvailableException
| TransportNotRegisteredException | RemoteException e) {
@@ -3194,6 +3201,11 @@ public class UserBackupManagerService {
}
}
+ @VisibleForTesting
+ BackupManagerMonitorEventSender getBMMEventSender(IBackupManagerMonitor monitor) {
+ return new BackupManagerMonitorEventSender(monitor);
+ }
+
/** User-configurable enabling/disabling of backups. */
public void setBackupEnabled(boolean enable) {
setBackupEnabled(enable, /* persistToDisk */ true);
@@ -4152,6 +4164,7 @@ public class UserBackupManagerService {
}
}
dumpInternal(pw);
+ dumpBMMEvents(pw);
} finally {
Binder.restoreCallingIdentity(identityToken);
}
@@ -4169,6 +4182,23 @@ public class UserBackupManagerService {
}
}
+ private void dumpBMMEvents(PrintWriter pw) {
+ BackupManagerMonitorDumpsysUtils bm =
+ new BackupManagerMonitorDumpsysUtils();
+ File events = bm.getBMMEventsFile();
+ pw.println("START OF BACKUP MANAGER MONITOR EVENTS");
+ try (BufferedReader reader = new BufferedReader(new FileReader(events))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ pw.println(line);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "IO Exception when reading BMM events from file: " + e);
+ pw.println("IO Exception when reading BMM events from file");
+ }
+ pw.println("END OF BACKUP MANAGER MONITOR EVENTS");
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
private void dumpInternal(PrintWriter pw) {
// Add prefix for only non-system users so that system user dumpsys is the same as before
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index ad29422501c6..12712063e344 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -23,13 +23,11 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST
import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME;
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupTransport;
import android.app.backup.FullBackupDataOutput;
-import android.app.backup.IBackupManagerMonitor;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -44,7 +42,7 @@ import com.android.server.backup.OperationStorage.OpType;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.remote.RemoteCall;
import com.android.server.backup.utils.BackupEligibilityRules;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.android.server.backup.utils.FullBackupUtils;
import java.io.File;
@@ -69,7 +67,7 @@ public class FullBackupEngine {
private final int mTransportFlags;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
private final BackupEligibilityRules mBackupEligibilityRules;
- @Nullable private final IBackupManagerMonitor mMonitor;
+ private final BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
class FullBackupRunner implements Runnable {
private final @UserIdInt int mUserId;
@@ -198,7 +196,7 @@ public class FullBackupEngine {
int opToken,
int transportFlags,
BackupEligibilityRules backupEligibilityRules,
- IBackupManagerMonitor monitor) {
+ BackupManagerMonitorEventSender backupManagerMonitorEventSender) {
this.backupManagerService = backupManagerService;
mOutput = output;
mPreflightHook = preflightHook;
@@ -213,7 +211,7 @@ public class FullBackupEngine {
backupManagerService.getAgentTimeoutParameters(),
"Timeout parameters cannot be null");
mBackupEligibilityRules = backupEligibilityRules;
- mMonitor = monitor;
+ mBackupManagerMonitorEventSender = backupManagerMonitorEventSender;
}
public int preflightCheck() throws RemoteException {
@@ -270,7 +268,7 @@ public class FullBackupEngine {
result = BackupTransport.TRANSPORT_OK;
}
- BackupManagerMonitorUtils.monitorAgentLoggingResults(mMonitor, mPkg, mAgent);
+ mBackupManagerMonitorEventSender.monitorAgentLoggingResults(mPkg, mAgent);
} catch (IOException e) {
Slog.e(TAG, "Error backing up " + mPkg.packageName + ": " + e.getMessage());
result = BackupTransport.AGENT_ERROR;
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index cba1e299ff58..dc6709141b25 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -40,6 +40,7 @@ import com.android.server.backup.KeyValueAdbBackupEngine;
import com.android.server.backup.OperationStorage;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.utils.BackupEligibilityRules;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.android.server.backup.utils.PasswordUtils;
import java.io.ByteArrayOutputStream;
@@ -421,7 +422,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
mCurrentOpToken,
/*transportFlags=*/ 0,
mBackupEligibilityRules,
- /* monitor= */ null);
+ new BackupManagerMonitorEventSender(null));
sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
// Don't need to check preflight result as there is no preflight hook.
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 162046a66560..6aed9aa15860 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -54,7 +54,7 @@ import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.utils.BackupEligibilityRules;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.android.server.backup.utils.BackupObserverUtils;
import com.google.android.collect.Sets;
@@ -153,7 +153,6 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
CountDownLatch mLatch;
FullBackupJob mJob; // if a scheduled job needs to be finished afterwards
IBackupObserver mBackupObserver;
- @Nullable private IBackupManagerMonitor mMonitor;
boolean mUserInitiated;
SinglePackageBackupRunner mBackupRunner;
private final int mBackupRunnerOpToken;
@@ -167,6 +166,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
private final int mCurrentOpToken;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
private final BackupEligibilityRules mBackupEligibilityRules;
+ private BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
public PerformFullTransportBackupTask(UserBackupManagerService backupManagerService,
OperationStorage operationStorage,
@@ -185,11 +185,12 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
mJob = runningJob;
mPackages = new ArrayList<>(whichPackages.length);
mBackupObserver = backupObserver;
- mMonitor = monitor;
mListener = (listener != null) ? listener : OnTaskFinishedListener.NOP;
mUserInitiated = userInitiated;
mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken();
+ mBackupManagerMonitorEventSender =
+ new BackupManagerMonitorEventSender(monitor);
mAgentTimeoutParameters = Objects.requireNonNull(
backupManagerService.getAgentTimeoutParameters(),
"Timeout parameters cannot be null");
@@ -218,7 +219,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring ineligible package " + pkg);
}
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -233,7 +234,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
Slog.d(TAG, "Ignoring full-data backup of key/value participant "
+ pkg);
}
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -248,7 +249,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring stopped package " + pkg);
}
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -260,7 +261,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
mPackages.add(info);
} catch (NameNotFoundException e) {
Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -356,8 +357,8 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
} else {
monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
}
- mMonitor = BackupManagerMonitorUtils
- .monitorEvent(mMonitor, monitoringEvent, null,
+ mBackupManagerMonitorEventSender
+ .monitorEvent(monitoringEvent, null,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
null);
mUpdateSchedule = false;
@@ -369,7 +370,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
if (transport == null) {
Slog.w(TAG, "Transport not present; full data backup not performed");
backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT,
mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
null);
@@ -378,9 +379,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
// In some cases there may not be a monitor passed in when creating this task. So, if we
// don't have one already we ask the transport for a monitor.
- if (mMonitor == null) {
+ if (mBackupManagerMonitorEventSender.getMonitor() == null) {
try {
- mMonitor = transport.getBackupManagerMonitor();
+ mBackupManagerMonitorEventSender
+ .setMonitor(transport.getBackupManagerMonitor());
} catch (RemoteException e) {
Slog.i(TAG, "Failed to retrieve monitor from transport");
}
@@ -457,11 +459,11 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
+ packageName + ": " + preflightResult
+ ", not running backup.");
}
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- BackupManagerMonitorUtils.putMonitoringExtra(null,
+ mBackupManagerMonitorEventSender.putMonitoringExtra(null,
BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR,
preflightResult));
backupPackageStatus = (int) preflightResult;
@@ -492,7 +494,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
Slog.w(TAG, "Package hit quota limit in-flight " + packageName
+ ": " + totalRead + " of " + quota);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
@@ -647,11 +649,11 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
} catch (Exception e) {
backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
Slog.w(TAG, "Exception trying full transport backup", e);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- BackupManagerMonitorUtils.putMonitoringExtra(null,
+ mBackupManagerMonitorEventSender.putMonitoringExtra(null,
BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP,
Log.getStackTraceString(e)));
@@ -885,7 +887,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
mCurrentOpToken,
mTransportFlags,
mBackupEligibilityRules,
- mMonitor);
+ mBackupManagerMonitorEventSender);
try {
try {
if (!mIsCancelled) {
@@ -967,7 +969,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
Slog.w(TAG, "Full backup cancel of " + mTarget.packageName);
}
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL,
mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
mIsCancelled = true;
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
index 4632cb0e51e2..20c8cf6c6923 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
@@ -32,7 +32,7 @@ import com.android.server.backup.BackupManagerService;
import com.android.server.backup.DataChangedJournal;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.remote.RemoteResult;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.android.server.backup.utils.BackupObserverUtils;
import java.io.File;
@@ -65,21 +65,21 @@ public class KeyValueBackupReporter {
private final UserBackupManagerService mBackupManagerService;
private final IBackupObserver mObserver;
- @Nullable private IBackupManagerMonitor mMonitor;
+ private final BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
KeyValueBackupReporter(
UserBackupManagerService backupManagerService,
IBackupObserver observer,
- @Nullable IBackupManagerMonitor monitor) {
+ BackupManagerMonitorEventSender backupManagerMonitorEventSender) {
mBackupManagerService = backupManagerService;
mObserver = observer;
- mMonitor = monitor;
+ mBackupManagerMonitorEventSender = backupManagerMonitorEventSender;
}
/** Returns the monitor or {@code null} if we lost connection to it. */
@Nullable
IBackupManagerMonitor getMonitor() {
- return mMonitor;
+ return mBackupManagerMonitorEventSender.getMonitor();
}
IBackupObserver getObserver() {
@@ -208,13 +208,11 @@ public class KeyValueBackupReporter {
void onAgentIllegalKey(PackageInfo packageInfo, String key) {
String packageName = packageInfo.packageName;
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, "bad key");
- mMonitor =
- BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY,
packageInfo,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- BackupManagerMonitorUtils.putMonitoringExtra(
+ mBackupManagerMonitorEventSender.putMonitoringExtra(
null, BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY, key));
BackupObserverUtils.sendBackupOnPackageResult(
mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);
@@ -254,13 +252,11 @@ public class KeyValueBackupReporter {
if (MORE_DEBUG) {
Slog.i(TAG, "No backup data written, not calling transport");
}
- mMonitor =
- BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND,
- packageInfo,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND,
+ packageInfo,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
}
void onPackageBackupComplete(String packageName, long size) {
@@ -291,8 +287,7 @@ public class KeyValueBackupReporter {
void onPackageBackupNonIncrementalRequired(PackageInfo packageInfo) {
Slog.i(TAG, "Transport lost data, retrying package");
- BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED,
packageInfo,
BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
@@ -335,28 +330,24 @@ public class KeyValueBackupReporter {
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
// Time-out used to be implemented as cancel w/ cancelAll = false.
// TODO: Change monitoring event to reflect time-out as an event itself.
- mMonitor =
- BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
- packageInfo,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
- BackupManagerMonitorUtils.putMonitoringExtra(
- null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, false));
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
+ packageInfo,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ mBackupManagerMonitorEventSender.putMonitoringExtra(
+ null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, false));
}
void onAgentCancelled(@Nullable PackageInfo packageInfo) {
String packageName = getPackageName(packageInfo);
Slog.i(TAG, "Cancel backing up " + packageName);
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
- mMonitor =
- BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
- packageInfo,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
- BackupManagerMonitorUtils.putMonitoringExtra(
- null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, true));
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
+ packageInfo,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ mBackupManagerMonitorEventSender.putMonitoringExtra(
+ null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, true));
}
void onAgentResultError(@Nullable PackageInfo packageInfo) {
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 41e8092436b5..3a6e1cafa505 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -68,7 +68,7 @@ import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.utils.BackupEligibilityRules;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import libcore.io.IoUtils;
@@ -225,7 +225,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
boolean nonIncremental,
BackupEligibilityRules backupEligibilityRules) {
KeyValueBackupReporter reporter =
- new KeyValueBackupReporter(backupManagerService, observer, monitor);
+ new KeyValueBackupReporter(backupManagerService, observer,
+ new BackupManagerMonitorEventSender(monitor));
KeyValueBackupTask task =
new KeyValueBackupTask(
backupManagerService,
@@ -698,8 +699,9 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
try {
extractAgentData(mCurrentPackage);
- BackupManagerMonitorUtils.monitorAgentLoggingResults(
- mReporter.getMonitor(), mCurrentPackage, mAgent);
+ BackupManagerMonitorEventSender mBackupManagerMonitorEventSender =
+ new BackupManagerMonitorEventSender(mReporter.getMonitor());
+ mBackupManagerMonitorEventSender.monitorAgentLoggingResults(mCurrentPackage, mAgent);
int status = sendDataToTransport(mCurrentPackage);
cleanUpAgentForTransportStatus(status);
} catch (AgentException | TaskException e) {
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 8cbb5dc03b9e..e04bf11dad9f 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -16,6 +16,8 @@
package com.android.server.backup.restore;
+import static android.app.backup.BackupAnnotations.OperationType.RESTORE;
+
import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
import static com.android.server.backup.BackupManagerService.TAG;
@@ -30,6 +32,7 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.Nullable;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
+import android.app.backup.BackupAnnotations;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupManagerMonitor;
@@ -70,7 +73,7 @@ import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.utils.BackupEligibilityRules;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import libcore.io.IoUtils;
@@ -84,7 +87,6 @@ import java.util.Objects;
import java.util.Set;
public class PerformUnifiedRestoreTask implements BackupRestoreTask {
-
private UserBackupManagerService backupManagerService;
private final OperationStorage mOperationStorage;
private final int mUserId;
@@ -98,8 +100,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Restore observer; may be null
private IRestoreObserver mObserver;
- // BackuoManagerMonitor; may be null
- private IBackupManagerMonitor mMonitor;
+ private BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
// Token identifying the dataset to the transport
private long mToken;
@@ -181,6 +182,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
mUserId = 0;
mBackupEligibilityRules = null;
this.backupManagerService = backupManagerService;
+ mBackupManagerMonitorEventSender =
+ new BackupManagerMonitorEventSender(/*monitor*/null);
}
// This task can assume that the wakelock is properly held for it and doesn't have to worry
@@ -208,7 +211,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
mTransportConnection = transportConnection;
mObserver = observer;
- mMonitor = monitor;
+ mBackupManagerMonitorEventSender =
+ new BackupManagerMonitorEventSender(monitor);
mToken = restoreSetToken;
mPmToken = pmToken;
mTargetPackage = targetPackage;
@@ -410,8 +414,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// If the requester of the restore has not passed in a monitor, we ask the transport
// for one.
- if (mMonitor == null) {
- mMonitor = transport.getBackupManagerMonitor();
+ if (mBackupManagerMonitorEventSender.getMonitor() == null) {
+ mBackupManagerMonitorEventSender.setMonitor(transport.getBackupManagerMonitor());
}
mStatus = transport.startRestore(mToken, packages);
@@ -425,10 +429,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
RestoreDescription desc = transport.nextRestorePackage();
if (desc == null) {
Slog.e(TAG, "No restore metadata available; halting");
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE,
mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
mStatus = BackupTransport.TRANSPORT_ERROR;
executeNextState(UnifiedRestoreState.FINAL);
return;
@@ -437,10 +443,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
desc.getPackageName())) {
Slog.e(TAG, "Required package metadata but got "
+ desc.getPackageName());
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED,
mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
mStatus = BackupTransport.TRANSPORT_ERROR;
executeNextState(UnifiedRestoreState.FINAL);
return;
@@ -472,10 +480,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// the restore operation.
if (!mPmAgent.hasMetadata()) {
Slog.e(TAG, "PM agent has no metadata, so not restoring");
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA,
mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
PACKAGE_MANAGER_SENTINEL,
"Package manager restore metadata missing");
@@ -492,10 +502,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
} catch (Exception e) {
// If we lost the transport at any time, halt
Slog.e(TAG, "Unable to contact transport for restore: " + e.getMessage());
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT,
null,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ monitoringExtras);
mStatus = BackupTransport.TRANSPORT_ERROR;
backupManagerService.getBackupHandler().removeMessages(
MSG_BACKUP_RESTORE_STEP, this);
@@ -552,11 +564,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Whoops, we thought we could restore this package but it
// turns out not to be present. Skip it.
Slog.e(TAG, "Package not present: " + pkgName);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_PRESENT,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
"Package missing on device");
nextState = UnifiedRestoreState.RUNNING_QUEUE;
@@ -572,13 +585,15 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
String message = "Source version " + metaInfo.versionCode
+ " > installed version " + mCurrentPackage.getLongVersionCode();
Slog.w(TAG, "Package " + pkgName + ": " + message);
- Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
+ Bundle monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
+ null,
BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
metaInfo.versionCode);
- monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
+ monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
monitoringExtras,
BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, false);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ monitoringExtras = addRestoreOperationTypeToEvent(monitoringExtras);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -593,13 +608,15 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
+ " > installed version " + mCurrentPackage.getLongVersionCode()
+ " but restoreAnyVersion");
}
- Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
+ Bundle monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
+ null,
BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
metaInfo.versionCode);
- monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
+ monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
monitoringExtras,
BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, true);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ monitoringExtras = addRestoreOperationTypeToEvent(monitoringExtras);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -652,9 +669,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
Slog.i(TAG, "Data exists for package " + packageName
+ " but app has no agent; skipping");
}
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_APP_HAS_NO_AGENT, mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Package has no agent");
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
@@ -665,9 +683,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage, pmi)) {
Slog.w(TAG, "Signature mismatch restoring " + packageName);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Signature mismatch");
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
@@ -681,9 +701,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
mBackupEligibilityRules.getBackupDestination());
if (mAgent == null) {
Slog.w(TAG, "Can't find backup agent for " + packageName);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_CANT_FIND_AGENT, mCurrentPackage,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Restore agent missing");
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
@@ -941,8 +963,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
EventLog.writeEvent(EventLogTags.FULL_RESTORE_PACKAGE,
mCurrentPackage.packageName);
- mEngine = new FullRestoreEngine(backupManagerService, mOperationStorage, this, null,
- mMonitor, mCurrentPackage, false, mEphemeralOpToken, false,
+ mEngine = new FullRestoreEngine(backupManagerService, mOperationStorage,
+ this, null, mBackupManagerMonitorEventSender.getMonitor(),
+ mCurrentPackage, false, mEphemeralOpToken, false,
mBackupEligibilityRules);
mEngineThread = new FullRestoreEngineThread(mEngine, mEnginePipes[0]);
@@ -1095,10 +1118,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
if (DEBUG) {
Slog.w(TAG, "Full-data restore target timed out; shutting down");
}
-
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_TIMEOUT,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
+ mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ monitoringExtras);
mEngineThread.handleTimeout();
IoUtils.closeQuietly(mEnginePipes[1]);
@@ -1322,7 +1346,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Ask the agent for logs after doRestoreFinished() has completed executing to allow
// it to finalize its logs.
- BackupManagerMonitorUtils.monitorAgentLoggingResults(mMonitor, mCurrentPackage,
+ mBackupManagerMonitorEventSender.monitorAgentLoggingResults(mCurrentPackage,
mAgent);
// Just go back to running the restore queue
@@ -1358,9 +1382,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
public void handleCancel(boolean cancelAll) {
mOperationStorage.removeOperation(mEphemeralOpToken);
Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
+ mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
mCurrentPackage.packageName, "restore timeout");
// Handle like an agent that threw on invocation: wipe it and go on to the next
@@ -1433,4 +1458,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
}
}
+
+ private Bundle addRestoreOperationTypeToEvent (@Nullable Bundle extra) {
+ return mBackupManagerMonitorEventSender.putMonitoringExtra(
+ extra,
+ BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE, RESTORE);
+ }
}
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
new file mode 100644
index 000000000000..0b55ca21371b
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.utils;
+
+import android.app.backup.BackupAnnotations;
+import android.app.backup.BackupManagerMonitor;
+import android.app.backup.BackupRestoreEventLogger;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Slog;
+
+import com.android.internal.util.FastPrintWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Map;
+
+
+/*
+ * Util class to parse a BMM event and write it to a text file, to be the printed in
+ * the backup dumpsys
+ *
+ * Note: this class is note thread safe
+ */
+public class BackupManagerMonitorDumpsysUtils {
+
+ private static final String TAG = "BackupManagerMonitorDumpsysUtils";
+ // Name of the subdirectory where the text file containing the BMM events will be stored.
+ // Same as {@link UserBackupManagerFiles}
+ private static final String BACKUP_PERSISTENT_DIR = "backup";
+
+ /**
+ * Parses the BackupManagerMonitor bundle for a RESTORE event in a series of strings that
+ * will be persisted in a text file and printed in the dumpsys.
+ *
+ * If the evenntBundle passed is not a RESTORE event, return early
+ *
+ * Key information related to the event:
+ * - Timestamp (HAS TO ALWAYS BE THE FIRST LINE OF EACH EVENT)
+ * - Event ID
+ * - Event Category
+ * - Operation type
+ * - Package name (can be null)
+ * - Agent logs (if available)
+ *
+ * Example of formatting:
+ * RESTORE Event: [2023-08-18 17:16:00.735] Agent - Agent logging results
+ * Package name: com.android.wallpaperbackup
+ * Agent Logs:
+ * Data Type: wlp_img_system
+ * Item restored: 0/1
+ * Agent Error - Category: no_wallpaper, Count: 1
+ * Data Type: wlp_img_lock
+ * Item restored: 0/1
+ * Agent Error - Category: no_wallpaper, Count: 1
+ */
+ public void parseBackupManagerMonitorRestoreEventForDumpsys(Bundle eventBundle) {
+ if (eventBundle == null) {
+ return;
+ }
+
+ if (!isOpTypeRestore(eventBundle)) {
+ //We only log Restore events
+ return;
+ }
+
+ if (!eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_ID)
+ || !eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY)) {
+ Slog.w(TAG, "Event id and category are not optional fields.");
+ return;
+ }
+ File bmmEvents = getBMMEventsFile();
+
+ try (FileOutputStream out = new FileOutputStream(bmmEvents, /*append*/ true);
+ PrintWriter pw = new FastPrintWriter(out);) {
+
+ int eventCategory = eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY);
+ int eventId = eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID);
+
+ if (eventId == BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS &&
+ !hasAgentLogging(eventBundle)) {
+ // Do not record an empty agent logging event
+ return;
+ }
+
+ pw.println("RESTORE Event: [" + timestamp() + "] " +
+ getCategory(eventCategory) + " - " +
+ getId(eventId));
+
+ if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME)) {
+ pw.println("\tPackage name: "
+ + eventBundle.getString(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME));
+ }
+
+ // TODO(b/296818666): add extras to the events
+ addAgentLogsIfAvailable(eventBundle, pw);
+ } catch (java.io.IOException e) {
+ Slog.e(TAG, "IO Exception when writing BMM events to file: " + e);
+ }
+
+ }
+
+ private boolean hasAgentLogging(Bundle eventBundle) {
+ if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS)) {
+ ArrayList<BackupRestoreEventLogger.DataTypeResult> agentLogs =
+ eventBundle.getParcelableArrayList(
+ BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS);
+
+ return !agentLogs.isEmpty();
+ }
+ return false;
+ }
+
+ /**
+ * Extracts agent logs from the BackupManagerMonitor event. These logs detail:
+ * - the data type for the agent
+ * - the count of successfully restored items
+ * - the count of items that failed to restore
+ * - the metadata associated with this datatype
+ * - any errors
+ */
+ private void addAgentLogsIfAvailable(Bundle eventBundle, PrintWriter pw) {
+ if (hasAgentLogging(eventBundle)) {
+ pw.println("\tAgent Logs:");
+ ArrayList<BackupRestoreEventLogger.DataTypeResult> agentLogs =
+ eventBundle.getParcelableArrayList(
+ BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS);
+ for (BackupRestoreEventLogger.DataTypeResult result : agentLogs) {
+ int totalItems = result.getFailCount() + result.getSuccessCount();
+ pw.println("\t\tData Type: " + result.getDataType());
+ pw.println("\t\t\tItem restored: " + result.getSuccessCount() + "/" +
+ totalItems);
+ for (Map.Entry<String, Integer> entry : result.getErrors().entrySet()) {
+ pw.println("\t\t\tAgent Error - Category: " +
+ entry.getKey() + ", Count: " + entry.getValue());
+ }
+ }
+ }
+ }
+
+ /*
+ * Get the path of the text files which stores the BMM events
+ */
+ public File getBMMEventsFile() {
+ File dataDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
+ File fname = new File(dataDir, "bmmevents.txt");
+ return fname;
+ }
+
+ private String timestamp() {
+ long currentTime = System.currentTimeMillis();
+ Date date = new Date(currentTime);
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ return dateFormat.format(date);
+ }
+
+ private String getCategory(int code) {
+ String category = switch (code) {
+ case BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT -> "Transport";
+ case BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT -> "Agent";
+ case BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY ->
+ "Backup Manager Policy";
+ default -> "Unknown category code: " + code;
+ };
+ return category;
+ }
+
+ private String getId(int code) {
+ String id = switch (code) {
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL -> "Full backup cancel";
+ case BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY -> "Illegal key";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND -> "No data to send";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE -> "Package ineligible";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT ->
+ "Package key-value participant";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED -> "Package stopped";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND -> "Package not found";
+ case BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED -> "Backup disabled";
+ case BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED ->
+ "Device not provisioned";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT ->
+ "Package transport not present";
+ case BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT -> "Error preflight";
+ case BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT -> "Quota hit preflight";
+ case BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP -> "Exception full backup";
+ case BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL ->
+ "Key-value backup cancel";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE ->
+ "No restore metadata available";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED ->
+ "No PM metadata received";
+ case BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA ->
+ "PM agent has no metadata";
+ case BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT -> "Lost transport";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_PRESENT -> "Package not present";
+ case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER ->
+ "Restore version higher";
+ case BackupManagerMonitor.LOG_EVENT_ID_APP_HAS_NO_AGENT -> "App has no agent";
+ case BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH -> "Signature mismatch";
+ case BackupManagerMonitor.LOG_EVENT_ID_CANT_FIND_AGENT -> "Can't find agent";
+ case BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT ->
+ "Key-value restore timeout";
+ case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION -> "Restore any version";
+ case BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH -> "Versions match";
+ case BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER ->
+ "Version of backup older";
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH ->
+ "Full restore signature mismatch";
+ case BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT -> "System app no agent";
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE ->
+ "Full restore allow backup false";
+ case BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED -> "APK not installed";
+ case BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK ->
+ "Cannot restore without APK";
+ case BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE -> "Missing signature";
+ case BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE ->
+ "Expected different package";
+ case BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION -> "Unknown version";
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_TIMEOUT -> "Full restore timeout";
+ case BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST -> "Corrupt manifest";
+ case BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH ->
+ "Widget metadata mismatch";
+ case BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION ->
+ "Widget unknown version";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES -> "No packages";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL -> "Transport is null";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED ->
+ "Transport non-incremental backup required";
+ case BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS -> "Agent logging results";
+ default -> "Unknown log event ID: " + code;
+ };
+ return id;
+ }
+
+ private boolean isOpTypeRestore(Bundle eventBundle) {
+ return switch (eventBundle.getInt(
+ BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE, -1)) {
+ case BackupAnnotations.OperationType.RESTORE -> true;
+ default -> false;
+ };
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
index 439b83687b8f..92e3107b6977 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
@@ -25,7 +25,6 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING
import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.TAG;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.IBackupAgent;
import android.app.backup.BackupAnnotations.OperationType;
@@ -37,6 +36,7 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import java.util.List;
@@ -44,9 +44,9 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
- * Utility methods to communicate with BackupManagerMonitor.
+ * Utility methods to log BackupManagerMonitor events.
*/
-public class BackupManagerMonitorUtils {
+public class BackupManagerMonitorEventSender {
/**
* Timeout for how long we wait before we give up on getting logs from a {@link IBackupAgent}.
* We expect this to be very fast since the agent immediately returns whatever logs have been
@@ -54,51 +54,77 @@ public class BackupManagerMonitorUtils {
* for non-essential logs.
*/
private static final int AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS = 500;
+ @Nullable private IBackupManagerMonitor mMonitor;
+ private final BackupManagerMonitorDumpsysUtils mBackupManagerMonitorDumpsysUtils;
+ public BackupManagerMonitorEventSender(@Nullable IBackupManagerMonitor monitor) {
+ mMonitor = monitor;
+ mBackupManagerMonitorDumpsysUtils = new BackupManagerMonitorDumpsysUtils();
+ }
+
+ @VisibleForTesting
+ BackupManagerMonitorEventSender(@Nullable IBackupManagerMonitor monitor,
+ BackupManagerMonitorDumpsysUtils backupManagerMonitorDumpsysUtils) {
+ mMonitor = monitor;
+ mBackupManagerMonitorDumpsysUtils = backupManagerMonitorDumpsysUtils;
+ }
+
+ public void setMonitor(IBackupManagerMonitor monitor) {
+ mMonitor = monitor;
+ }
+
+ public IBackupManagerMonitor getMonitor() {
+ return mMonitor;
+ }
/**
* Notifies monitor about the event.
*
* Calls {@link IBackupManagerMonitor#onEvent(Bundle)} with a bundle representing current event.
*
- * @param monitor - implementation of {@link IBackupManagerMonitor} to notify.
* @param id - event id.
* @param pkg - package event is related to.
* @param category - event category.
* @param extras - additional event data.
- * @return <code>monitor</code> if call succeeded and <code>null</code> otherwise.
*/
- @Nullable
- public static IBackupManagerMonitor monitorEvent(
- @Nullable IBackupManagerMonitor monitor,
+ public void monitorEvent(
int id,
PackageInfo pkg,
int category,
Bundle extras) {
- if (monitor != null) {
- try {
- Bundle bundle = new Bundle();
- bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id);
- bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, category);
- if (pkg != null) {
- bundle.putString(EXTRA_LOG_EVENT_PACKAGE_NAME,
- pkg.packageName);
- bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION,
- pkg.versionCode);
- bundle.putLong(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION,
- pkg.getLongVersionCode());
- }
- if (extras != null) {
- bundle.putAll(extras);
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id);
+ bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, category);
+ if (pkg != null) {
+ bundle.putString(EXTRA_LOG_EVENT_PACKAGE_NAME,
+ pkg.packageName);
+ bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION,
+ pkg.versionCode);
+ bundle.putLong(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION,
+ pkg.getLongVersionCode());
+ }
+ if (extras != null) {
+ bundle.putAll(extras);
+ if (extras.containsKey(EXTRA_LOG_OPERATION_TYPE) &&
+ extras.getInt(EXTRA_LOG_OPERATION_TYPE) == OperationType.RESTORE){
+ mBackupManagerMonitorDumpsysUtils
+ .parseBackupManagerMonitorRestoreEventForDumpsys(bundle);
}
- monitor.onEvent(bundle);
- return monitor;
- } catch (RemoteException e) {
+ }
+
+ if (mMonitor != null) {
+ mMonitor.onEvent(bundle);
+ } else {
if (DEBUG) {
- Slog.w(TAG, "backup manager monitor went away");
+ Slog.w(TAG, "backup manager monitor is null unable to send event");
}
}
+ } catch (RemoteException e) {
+ mMonitor = null;
+ if (DEBUG) {
+ Slog.w(TAG, "backup manager monitor went away");
+ }
}
- return null;
}
/**
@@ -108,17 +134,12 @@ public class BackupManagerMonitorUtils {
* <p>Note that this method does two separate binder calls (one to the agent and one to the
* monitor).
*
- * @param monitor - implementation of {@link IBackupManagerMonitor} to notify.
* @param pkg - package the {@code agent} belongs to.
* @param agent - the {@link IBackupAgent} to retrieve logs from.
- * @return {@code null} if the monitor is null. {@code monitor} if we fail to retrieve the logs
- * from the {@code agent}. Otherwise, the result of {@link
- * #monitorEvent(IBackupManagerMonitor, int, PackageInfo, int, Bundle)}.
*/
- public static IBackupManagerMonitor monitorAgentLoggingResults(
- @Nullable IBackupManagerMonitor monitor, PackageInfo pkg, IBackupAgent agent) {
- if (monitor == null) {
- return null;
+ public void monitorAgentLoggingResults(PackageInfo pkg, IBackupAgent agent) {
+ if (mMonitor == null) {
+ Slog.i(TAG, "backup manager monitor is null unable to send event"+pkg);
}
try {
@@ -127,7 +148,7 @@ public class BackupManagerMonitorUtils {
AndroidFuture<Integer> operationTypeFuture = new AndroidFuture<>();
agent.getLoggerResults(resultsFuture);
agent.getOperationType(operationTypeFuture);
- return sendAgentLoggingResults(monitor, pkg,
+ sendAgentLoggingResults(pkg,
resultsFuture.get(AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS),
operationTypeFuture.get(AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS));
@@ -136,18 +157,15 @@ public class BackupManagerMonitorUtils {
} catch (Exception e) {
Slog.w(TAG, "Failed to retrieve logging results from agent", e);
}
- return monitor;
}
- public static IBackupManagerMonitor sendAgentLoggingResults(
- @NonNull IBackupManagerMonitor monitor, PackageInfo pkg, List<DataTypeResult> results,
+ public void sendAgentLoggingResults(PackageInfo pkg, List<DataTypeResult> results,
@OperationType int operationType) {
Bundle loggerResultsBundle = new Bundle();
loggerResultsBundle.putParcelableList(
EXTRA_LOG_AGENT_LOGGING_RESULTS, results);
loggerResultsBundle.putInt(EXTRA_LOG_OPERATION_TYPE, operationType);
- return monitorEvent(
- monitor,
+ monitorEvent(
LOG_EVENT_ID_AGENT_LOGGING_RESULTS,
pkg,
LOG_EVENT_CATEGORY_AGENT,
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index 71ca8ca24604..78a9952d066d 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -85,7 +85,8 @@ public class TarBackupReader {
private final InputStream mInputStream;
private final BytesReadListener mBytesReadListener;
- private IBackupManagerMonitor mMonitor;
+
+ private BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
// Widget blob to be restored out-of-band.
private byte[] mWidgetData = null;
@@ -94,7 +95,7 @@ public class TarBackupReader {
IBackupManagerMonitor monitor) {
mInputStream = inputStream;
mBytesReadListener = bytesReadListener;
- mMonitor = monitor;
+ mBackupManagerMonitorEventSender = new BackupManagerMonitorEventSender(monitor);
}
/**
@@ -323,24 +324,22 @@ public class TarBackupReader {
return sigs;
} else {
Slog.i(TAG, "Missing signature on backed-up package " + info.packageName);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_MISSING_SIGNATURE,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- BackupManagerMonitorUtils.putMonitoringExtra(null,
+ mBackupManagerMonitorEventSender.putMonitoringExtra(null,
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
}
} else {
Slog.i(TAG, "Expected package " + info.packageName
+ " but restore manifest claims " + manifestPackage);
- Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
+ Bundle monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
+ null, EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
+ monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
monitoringExtras,
EXTRA_LOG_MANIFEST_PACKAGE_NAME, manifestPackage);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -349,12 +348,11 @@ public class TarBackupReader {
} else {
Slog.i(TAG, "Unknown restore manifest version " + version
+ " for package " + info.packageName);
- Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
- EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
- EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ Bundle monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
+ null, EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
+ monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
+ monitoringExtras, EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -363,12 +361,12 @@ public class TarBackupReader {
}
} catch (NumberFormatException e) {
Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- BackupManagerMonitorUtils.putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
+ mBackupManagerMonitorEventSender.putMonitoringExtra(null,
+ EXTRA_LOG_EVENT_PACKAGE_NAME,
info.packageName));
} catch (IllegalArgumentException e) {
Slog.w(TAG, e.getMessage());
@@ -436,8 +434,7 @@ public class TarBackupReader {
if ((pkgInfo.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
Slog.i(TAG, "Package has restoreAnyVersion; taking data");
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_RESTORE_ANY_VERSION,
pkgInfo,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -446,8 +443,7 @@ public class TarBackupReader {
} else if (pkgInfo.getLongVersionCode() >= info.version) {
Slog.i(TAG, "Sig + version match; taking data");
policy = RestorePolicy.ACCEPT;
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_VERSIONS_MATCH,
pkgInfo,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -466,12 +462,11 @@ public class TarBackupReader {
} else {
Slog.i(TAG, "Data requires newer version "
+ info.version + "; ignoring");
- mMonitor = BackupManagerMonitorUtils
- .monitorEvent(mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER,
pkgInfo,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- BackupManagerMonitorUtils
+ mBackupManagerMonitorEventSender
.putMonitoringExtra(
null,
EXTRA_LOG_OLD_VERSION,
@@ -484,8 +479,7 @@ public class TarBackupReader {
Slog.w(TAG, "Restore manifest signatures do not match "
+ "installed application for "
+ info.packageName);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH,
pkgInfo,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -494,8 +488,7 @@ public class TarBackupReader {
} else {
Slog.w(TAG, "Package " + info.packageName
+ " is system level with no agent");
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_SYSTEM_APP_NO_AGENT,
pkgInfo,
LOG_EVENT_CATEGORY_AGENT,
@@ -506,8 +499,7 @@ public class TarBackupReader {
Slog.i(TAG,
"Restore manifest from " + info.packageName + " but allowBackup=false");
}
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE,
pkgInfo,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -526,14 +518,13 @@ public class TarBackupReader {
} else {
policy = RestorePolicy.IGNORE;
}
- Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
+ Bundle monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
null,
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
+ monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
monitoringExtras,
EXTRA_LOG_POLICY_ALLOW_APKS, allowApks);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_APK_NOT_INSTALLED,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -543,12 +534,11 @@ public class TarBackupReader {
if (policy == RestorePolicy.ACCEPT_IF_APK && !info.hasApk) {
Slog.i(TAG, "Cannot restore package " + info.packageName
+ " without the matching .apk");
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- BackupManagerMonitorUtils.putMonitoringExtra(null,
+ mBackupManagerMonitorEventSender.putMonitoringExtra(null,
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
}
@@ -632,12 +622,11 @@ public class TarBackupReader {
"Metadata mismatch: package " + info.packageName + " but widget data for "
+ pkg);
- Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
+ Bundle monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(null,
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
- monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
- BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(
+ monitoringExtras, BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg);
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -646,13 +635,12 @@ public class TarBackupReader {
} else {
Slog.w(TAG, "Unsupported metadata version " + version);
- Bundle monitoringExtras = BackupManagerMonitorUtils
+ Bundle monitoringExtras = mBackupManagerMonitorEventSender
.putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
info.packageName);
- monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
+ monitoringExtras = mBackupManagerMonitorEventSender.putMonitoringExtra(monitoringExtras,
EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
- mMonitor = BackupManagerMonitorUtils.monitorEvent(
- mMonitor,
+ mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION,
null,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -810,7 +798,7 @@ public class TarBackupReader {
}
public IBackupManagerMonitor getMonitor() {
- return mMonitor;
+ return mBackupManagerMonitorEventSender.getMonitor();
}
public byte[] getWidgetData() {
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index fd45d2423227..69647633eaff 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -313,14 +313,14 @@ class AssociationRequestsProcessor {
public void enableSystemDataSync(int associationId, int flags) {
AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- AssociationInfo updated = AssociationInfo.builder(association)
+ AssociationInfo updated = (new AssociationInfo.Builder(association))
.setSystemDataSyncFlags(association.getSystemDataSyncFlags() | flags).build();
mAssociationStore.updateAssociation(updated);
}
public void disableSystemDataSync(int associationId, int flags) {
AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- AssociationInfo updated = AssociationInfo.builder(association)
+ AssociationInfo updated = (new AssociationInfo.Builder(association))
.setSystemDataSyncFlags(association.getSystemDataSyncFlags() & (~flags)).build();
mAssociationStore.updateAssociation(updated);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 996c68b5bf83..1ce7d9691fb5 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -891,7 +891,7 @@ public class CompanionDeviceManagerService extends SystemService {
}
// AssociationInfo class is immutable: create a new AssociationInfo object with updated
// timestamp.
- association = AssociationInfo.builder(association)
+ association = (new AssociationInfo.Builder(association))
.setLastTimeConnected(System.currentTimeMillis())
.build();
mAssociationStore.updateAssociation(association);
@@ -945,7 +945,7 @@ public class CompanionDeviceManagerService extends SystemService {
// AssociationInfo class is immutable: create a new AssociationInfo object with updated
// flag.
- association = AssociationInfo.builder(association)
+ association = (new AssociationInfo.Builder(association))
.setNotifyOnDeviceNearby(active)
.build();
// Do not need to call {@link BleCompanionDeviceScanner#restartScan()} since it will
@@ -1016,7 +1016,7 @@ public class CompanionDeviceManagerService extends SystemService {
@Override
public void setAssociationTag(int associationId, String tag) {
AssociationInfo association = getAssociationWithCallerChecks(associationId);
- association = AssociationInfo.builder(association).setTag(tag).build();
+ association = (new AssociationInfo.Builder(association)).setTag(tag).build();
mAssociationStore.updateAssociation(association);
}
@@ -1255,7 +1255,7 @@ public class CompanionDeviceManagerService extends SystemService {
*/
private void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
// First: set revoked flag.
- association = AssociationInfo.builder(association)
+ association = (new AssociationInfo.Builder(association))
.setRevoked(true)
.build();
diff --git a/services/companion/java/com/android/server/companion/virtual/Android.bp b/services/companion/java/com/android/server/companion/virtual/Android.bp
new file mode 100644
index 000000000000..50a09b9a8ea9
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/Android.bp
@@ -0,0 +1,12 @@
+java_aconfig_library {
+ name: "virtualdevice_flags_lib",
+ aconfig_declarations: "virtualdevice_flags",
+}
+
+aconfig_declarations {
+ name: "virtualdevice_flags",
+ package: "com.android.server.companion.virtual",
+ srcs: [
+ "flags.aconfig",
+ ],
+} \ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/virtual/flags.aconfig b/services/companion/java/com/android/server/companion/virtual/flags.aconfig
new file mode 100644
index 000000000000..4fe4c870a283
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.companion.virtual"
+
+flag {
+ name: "dump_history"
+ namespace: "virtual_devices"
+ description: "This flag controls if a history of virtual devices is shown in dumpsys virtualdevices"
+ bug: "293114719"
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index f4f5c951faaa..d256aead97e8 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -580,7 +580,6 @@ public class PackageWatchdog {
PackageHealthObserverImpact.USER_IMPACT_LEVEL_10,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_50,
- PackageHealthObserverImpact.USER_IMPACT_LEVEL_60,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_100})
public @interface PackageHealthObserverImpact {
@@ -591,7 +590,6 @@ public class PackageWatchdog {
/* Actions having medium user impact, user of a device will likely notice. */
int USER_IMPACT_LEVEL_30 = 30;
int USER_IMPACT_LEVEL_50 = 50;
- int USER_IMPACT_LEVEL_60 = 60;
int USER_IMPACT_LEVEL_70 = 70;
/* Action has high user impact, a last resort, user of a device will be very frustrated. */
int USER_IMPACT_LEVEL_100 = 100;
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index c6e9a7d5e2e5..7acca19f9d79 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -456,7 +456,13 @@ public class VcnManagementService extends IVcnManagementService.Stub {
final List<SubscriptionInfo> subscriptionInfos = new ArrayList<>();
Binder.withCleanCallingIdentity(
() -> {
- subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup));
+ List<SubscriptionInfo> subsInGroup =
+ subMgr.getSubscriptionsInGroup(subscriptionGroup);
+ if (subsInGroup == null) {
+ logWtf("Received null from getSubscriptionsInGroup");
+ subsInGroup = Collections.emptyList();
+ }
+ subscriptionInfos.addAll(subsInGroup);
});
for (SubscriptionInfo info : subscriptionInfos) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 04ebb2b14af6..610b8af48cd1 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -156,6 +156,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private final PowerProfile mPowerProfile;
private final CpuScalingPolicies mCpuScalingPolicies;
+ private final BatteryStatsImpl.BatteryStatsConfig mBatteryStatsConfig;
final BatteryStatsImpl mStats;
final CpuWakeupStats mCpuWakeupStats;
private final BatteryUsageStatsStore mBatteryUsageStatsStore;
@@ -374,22 +375,24 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mPowerProfile = new PowerProfile(context);
mCpuScalingPolicies = new CpuScalingPolicyReader().read();
- mStats = new BatteryStatsImpl(systemDir, handler, this,
- this, mUserManagerUserInfoProvider, mPowerProfile, mCpuScalingPolicies);
- mWorker = new BatteryExternalStatsWorker(context, mStats);
- mStats.setExternalStatsSyncLocked(mWorker);
- mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
- com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
-
final boolean resetOnUnplugHighBatteryLevel = context.getResources().getBoolean(
com.android.internal.R.bool.config_batteryStatsResetOnUnplugHighBatteryLevel);
final boolean resetOnUnplugAfterSignificantCharge = context.getResources().getBoolean(
com.android.internal.R.bool.config_batteryStatsResetOnUnplugAfterSignificantCharge);
- mStats.setBatteryStatsConfig(
+ final long powerStatsThrottlePeriodCpu = context.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodCpu);
+ mBatteryStatsConfig =
new BatteryStatsImpl.BatteryStatsConfig.Builder()
.setResetOnUnplugHighBatteryLevel(resetOnUnplugHighBatteryLevel)
.setResetOnUnplugAfterSignificantCharge(resetOnUnplugAfterSignificantCharge)
- .build());
+ .setPowerStatsThrottlePeriodCpu(powerStatsThrottlePeriodCpu)
+ .build();
+ mStats = new BatteryStatsImpl(mBatteryStatsConfig, systemDir, handler, this,
+ this, mUserManagerUserInfoProvider, mPowerProfile, mCpuScalingPolicies);
+ mWorker = new BatteryExternalStatsWorker(context, mStats);
+ mStats.setExternalStatsSyncLocked(mWorker);
+ mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
mStats.startTrackingSystemServerCpuTime();
if (BATTERY_USAGE_STORE_ENABLED) {
@@ -2591,6 +2594,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
pw.println(" --proto: output as a binary protobuffer");
pw.println(" --model power-profile: use the power profile model"
+ " even if measured energy is available");
+ pw.println(" --sample: collect and dump a sample of stats for debugging purpose");
pw.println(" <package.name>: optional name of package to filter output by.");
pw.println(" -h: print this help text.");
pw.println("Battery stats (batterystats) commands:");
@@ -2623,6 +2627,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ private void dumpStatsSample(PrintWriter pw) {
+ mStats.dumpStatsSample(pw);
+ }
+
+ private void dumpAggregatedStats(PrintWriter pw) {
+ mStats.dumpAggregatedStats(pw, /* startTime */ 0, /* endTime */0);
+ }
+
private void dumpMeasuredEnergyStats(PrintWriter pw) {
// Wait for the completion of pending works if there is any
awaitCompletion();
@@ -2864,6 +2876,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mCpuWakeupStats.dump(new IndentingPrintWriter(pw, " "),
SystemClock.elapsedRealtime());
return;
+ } else if ("--sample".equals(arg)) {
+ dumpStatsSample(pw);
+ return;
+ } else if ("--aggregated".equals(arg)) {
+ dumpAggregatedStats(pw);
+ return;
} else if ("-a".equals(arg)) {
flags |= BatteryStats.DUMP_VERBOSE;
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
@@ -2924,6 +2942,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
+ mBatteryStatsConfig,
null, mStats.mHandler, null, null,
mUserManagerUserInfoProvider, mPowerProfile,
mCpuScalingPolicies);
@@ -2965,6 +2984,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
+ mBatteryStatsConfig,
null, mStats.mHandler, null, null,
mUserManagerUserInfoProvider, mPowerProfile,
mCpuScalingPolicies);
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 4cc147fcea03..9219623a031d 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -293,7 +293,8 @@ public class ContentProviderHelper {
return holder;
}
- // Don't expose providers between normal apps and instant apps
+ // Don't expose providers between normal apps and instant apps; enforce limited
+ // package visibility (introduced in Android 11); etc.
try {
if (AppGlobals.getPackageManager()
.resolveContentProvider(name, /*flags=*/ 0, userId) == null) {
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 0e4465dd7f6a..1d09dce1132a 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -87,7 +87,6 @@ public class SettingsToPropertiesMapper {
DeviceConfig.NAMESPACE_CAMERA_NATIVE,
DeviceConfig.NAMESPACE_CONFIGURATION,
DeviceConfig.NAMESPACE_CONNECTIVITY,
- DeviceConfig.NAMESPACE_CORE_EXPERIMENTS_TEAM_INTERNAL,
DeviceConfig.NAMESPACE_EDGETPU_NATIVE,
DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
@@ -115,19 +114,29 @@ public class SettingsToPropertiesMapper {
NAMESPACE_TETHERING_U_OR_LATER_NATIVE
};
+ // All the aconfig flags under the listed DeviceConfig scopes will be synced to native level.
+ @VisibleForTesting
+ static final String[] sDeviceConfigAconfigScopes = new String[] {
+ DeviceConfig.NAMESPACE_CORE_EXPERIMENTS_TEAM_INTERNAL,
+ };
+
private final String[] mGlobalSettings;
private final String[] mDeviceConfigScopes;
+ private final String[] mDeviceConfigAconfigScopes;
+
private final ContentResolver mContentResolver;
@VisibleForTesting
protected SettingsToPropertiesMapper(ContentResolver contentResolver,
String[] globalSettings,
- String[] deviceConfigScopes) {
+ String[] deviceConfigScopes,
+ String[] deviceConfigAconfigScopes) {
mContentResolver = contentResolver;
mGlobalSettings = globalSettings;
mDeviceConfigScopes = deviceConfigScopes;
+ mDeviceConfigAconfigScopes = deviceConfigAconfigScopes;
}
@VisibleForTesting
@@ -173,6 +182,36 @@ public class SettingsToPropertiesMapper {
return;
}
setProperty(propertyName, properties.getString(key, null));
+
+ // for legacy namespaces, they can also be used for trunk stable
+ // purposes. so push flag also into trunk stable slot in sys prop,
+ // later all legacy usage will be refactored and the sync to old
+ // sys prop slot can be removed.
+ String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
+ if (aconfigPropertyName == null) {
+ log("unable to construct system property for " + scope + "/"
+ + key);
+ return;
+ }
+ setProperty(aconfigPropertyName, properties.getString(key, null));
+ }
+ });
+ }
+
+ for (String deviceConfigAconfigScope : mDeviceConfigAconfigScopes) {
+ DeviceConfig.addOnPropertiesChangedListener(
+ deviceConfigAconfigScope,
+ AsyncTask.THREAD_POOL_EXECUTOR,
+ (DeviceConfig.Properties properties) -> {
+ String scope = properties.getNamespace();
+ for (String key : properties.getKeyset()) {
+ String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
+ if (aconfigPropertyName == null) {
+ log("unable to construct system property for " + scope + "/"
+ + key);
+ return;
+ }
+ setProperty(aconfigPropertyName, properties.getString(key, null));
}
});
}
@@ -180,7 +219,10 @@ public class SettingsToPropertiesMapper {
public static SettingsToPropertiesMapper start(ContentResolver contentResolver) {
SettingsToPropertiesMapper mapper = new SettingsToPropertiesMapper(
- contentResolver, sGlobalSettings, sDeviceConfigScopes);
+ contentResolver,
+ sGlobalSettings,
+ sDeviceConfigScopes,
+ sDeviceConfigAconfigScopes);
mapper.updatePropertiesFromSettings();
return mapper;
}
@@ -243,6 +285,28 @@ public class SettingsToPropertiesMapper {
return propertyName;
}
+ /**
+ * system property name constructing rule for aconfig flags:
+ * "persist.device_config.aconfig_flags.[category_name].[flag_name]".
+ * If the name contains invalid characters or substrings for system property name,
+ * will return null.
+ * @param categoryName
+ * @param flagName
+ * @return
+ */
+ @VisibleForTesting
+ static String makeAconfigFlagPropertyName(String categoryName, String flagName) {
+ String propertyName = SYSTEM_PROPERTY_PREFIX + "aconfig_flags." +
+ categoryName + "." + flagName;
+
+ if (!propertyName.matches(SYSTEM_PROPERTY_VALID_CHARACTERS_REGEX)
+ || propertyName.contains(SYSTEM_PROPERTY_INVALID_SUBSTRING)) {
+ return null;
+ }
+
+ return propertyName;
+ }
+
private void setProperty(String key, String value) {
// Check if need to clear the property
if (value == null) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index d89171d94478..4a523af142a4 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -391,7 +391,6 @@ public class AudioDeviceBroker {
final boolean wasBtScoRequested = isBluetoothScoRequested();
CommunicationRouteClient client;
-
// Save previous client route in case of failure to start BT SCO audio
AudioDeviceAttributes prevClientDevice = null;
boolean prevPrivileged = false;
@@ -1043,7 +1042,7 @@ public class AudioDeviceBroker {
synchronized (mBluetoothAudioStateLock) {
mBluetoothScoOn = on;
updateAudioHalBluetoothState();
- postUpdateCommunicationRouteClient(eventSource);
+ postUpdateCommunicationRouteClient(isBluetoothScoRequested(), eventSource);
}
}
@@ -1395,8 +1394,10 @@ public class AudioDeviceBroker {
MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
}
- /*package*/ void postUpdateCommunicationRouteClient(String eventSource) {
- sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource);
+ /*package*/ void postUpdateCommunicationRouteClient(
+ boolean wasBtScoRequested, String eventSource) {
+ sendILMsgNoDelay(MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
+ wasBtScoRequested ? 1 : 0, eventSource);
}
/*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
@@ -1708,7 +1709,8 @@ public class AudioDeviceBroker {
: AudioSystem.STREAM_DEFAULT);
if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
|| btInfo.mProfile == BluetoothProfile.HEARING_AID) {
- onUpdateCommunicationRouteClient("setBluetoothActiveDevice");
+ onUpdateCommunicationRouteClient(isBluetoothScoRequested(),
+ "setBluetoothActiveDevice");
}
}
}
@@ -1762,9 +1764,11 @@ public class AudioDeviceBroker {
case MSG_I_SET_MODE_OWNER:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
+ boolean wasBtScoRequested = isBluetoothScoRequested();
mAudioModeOwner = (AudioModeInfo) msg.obj;
if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
- onUpdateCommunicationRouteClient("setNewModeOwner");
+ onUpdateCommunicationRouteClient(
+ wasBtScoRequested, "setNewModeOwner");
}
}
}
@@ -1787,10 +1791,10 @@ public class AudioDeviceBroker {
}
break;
- case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
+ case MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- onUpdateCommunicationRouteClient((String) msg.obj);
+ onUpdateCommunicationRouteClient(msg.arg1 == 1, (String) msg.obj);
}
}
break;
@@ -1971,7 +1975,7 @@ public class AudioDeviceBroker {
private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42;
- private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
+ private static final int MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;
private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
@@ -2328,16 +2332,20 @@ public class AudioDeviceBroker {
*/
// @GuardedBy("mSetModeLock")
@GuardedBy("mDeviceStateLock")
- private void onUpdateCommunicationRouteClient(String eventSource) {
- updateCommunicationRoute(eventSource);
+ private void onUpdateCommunicationRouteClient(boolean wasBtScoRequested, String eventSource) {
CommunicationRouteClient crc = topCommunicationRouteClient();
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "
- + crc + " eventSource: " + eventSource);
+ Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
+ + " wasBtScoRequested: " + wasBtScoRequested + " eventSource: " + eventSource);
}
if (crc != null) {
setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
+ } else {
+ if (!isBluetoothScoRequested() && wasBtScoRequested) {
+ mBtHelper.stopBluetoothSco(eventSource);
+ }
+ updateCommunicationRoute(eventSource);
}
}
@@ -2401,7 +2409,11 @@ public class AudioDeviceBroker {
}
@GuardedBy("mDeviceStateLock")
- private boolean communnicationDeviceCompatOn() {
+ // LE Audio: For system server (Telecom) and APKs targeting S and above, we let the audio
+ // policy routing rules select the default communication device.
+ // For older APKs, we force LE Audio headset when connected as those APKs cannot select a LE
+ // Audiodevice explicitly.
+ private boolean communnicationDeviceLeAudioCompatOn() {
return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
&& !(CompatChanges.isChangeEnabled(
USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid)
@@ -2409,19 +2421,25 @@ public class AudioDeviceBroker {
}
@GuardedBy("mDeviceStateLock")
+ // Hearing Aid: For system server (Telecom) and IN_CALL mode we let the audio
+ // policy routing rules select the default communication device.
+ // For 3p apps and IN_COMMUNICATION mode we force Hearing aid when connected to maintain
+ // backwards compatibility
+ private boolean communnicationDeviceHaCompatOn() {
+ return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
+ && !(mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
+ }
+
+ @GuardedBy("mDeviceStateLock")
AudioDeviceAttributes getDefaultCommunicationDevice() {
- // For system server (Telecom) and APKs targeting S and above, we let the audio
- // policy routing rules select the default communication device.
- // For older APKs, we force Hearing Aid or LE Audio headset when connected as
- // those APKs cannot select a LE Audio or Hearing Aid device explicitly.
AudioDeviceAttributes device = null;
- if (communnicationDeviceCompatOn()) {
- // If both LE and Hearing Aid are active (thie should not happen),
- // priority to Hearing Aid.
+ // If both LE and Hearing Aid are active (thie should not happen),
+ // priority to Hearing Aid.
+ if (communnicationDeviceHaCompatOn()) {
device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID);
- if (device == null) {
- device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
- }
+ }
+ if (device == null && communnicationDeviceLeAudioCompatOn()) {
+ device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
}
return device;
}
@@ -2431,6 +2449,7 @@ public class AudioDeviceBroker {
List<AudioRecordingConfiguration> recordConfigs) {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
+ final boolean wasBtScoRequested = isBluetoothScoRequested();
boolean updateCommunicationRoute = false;
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
boolean wasActive = crc.isActive();
@@ -2459,7 +2478,8 @@ public class AudioDeviceBroker {
}
}
if (updateCommunicationRoute) {
- postUpdateCommunicationRouteClient("updateCommunicationRouteClientsActivity");
+ postUpdateCommunicationRouteClient(
+ wasBtScoRequested, "updateCommunicationRouteClientsActivity");
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3f50dfd33f42..5f15995687b7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -43,6 +43,7 @@ import static com.android.server.utils.EventLogger.Event.ALOGI;
import static com.android.server.utils.EventLogger.Event.ALOGW;
import android.Manifest;
+import android.annotation.EnforcePermission;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -7636,6 +7637,10 @@ public class AudioService extends IAudioService.Stub
throw new IllegalArgumentException("Illegal BluetoothProfile profile for device "
+ previousDevice + " -> " + newDevice + ". Got: " + profile);
}
+
+ sDeviceLogger.enqueue(new EventLogger.StringEvent("BlutoothActiveDeviceChanged for "
+ + BluetoothProfile.getProfileName(profile) + ", device update " + previousDevice
+ + " -> " + newDevice));
AudioDeviceBroker.BtDeviceChangedData data =
new AudioDeviceBroker.BtDeviceChangedData(newDevice, previousDevice, info,
"AudioService");
@@ -9685,6 +9690,9 @@ public class AudioService extends IAudioService.Stub
}
} else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "BluetoothAdapter ACTION_STATE_CHANGED with state " + state));
+
if (state == BluetoothAdapter.STATE_OFF ||
state == BluetoothAdapter.STATE_TURNING_OFF) {
mDeviceBroker.disconnectAllBluetoothProfiles();
@@ -9998,6 +10006,14 @@ public class AudioService extends IAudioService.Stub
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
}
+ /** see {@link AudioManager#getFocusDuckedUidsForTest()} */
+ @Override
+ @EnforcePermission("android.permission.QUERY_AUDIO_STATE")
+ public @NonNull List<Integer> getFocusDuckedUidsForTest() {
+ super.getFocusDuckedUidsForTest_enforcePermission();
+ return mPlaybackMonitor.getFocusDuckedUids();
+ }
+
public void unregisterAudioFocusClient(String clientId) {
new MediaMetrics.Item(mMetricsId + "focus")
.set(MediaMetrics.Property.CLIENT_NAME, clientId)
@@ -10014,6 +10030,68 @@ public class AudioService extends IAudioService.Stub
return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
}
+ /**
+ * Test method to return the duration of the fade out applied on the players of a focus loser
+ * @see AudioManager#getFocusFadeOutDurationForTest()
+ * @return the fade out duration, in ms
+ */
+ @EnforcePermission("android.permission.QUERY_AUDIO_STATE")
+ public long getFocusFadeOutDurationForTest() {
+ super.getFocusFadeOutDurationForTest_enforcePermission();
+ return mMediaFocusControl.getFocusFadeOutDurationForTest();
+ }
+
+ /**
+ * Test method to return the length of time after a fade out before the focus loser is unmuted
+ * (and is faded back in).
+ * @see AudioManager#getFocusUnmuteDelayAfterFadeOutForTest()
+ * @return the time gap after a fade out completion on focus loss, and fade in start, in ms
+ */
+ @Override
+ @EnforcePermission("android.permission.QUERY_AUDIO_STATE")
+ public long getFocusUnmuteDelayAfterFadeOutForTest() {
+ super.getFocusUnmuteDelayAfterFadeOutForTest_enforcePermission();
+ return mMediaFocusControl.getFocusUnmuteDelayAfterFadeOutForTest();
+ }
+
+ /**
+ * Test method to start preventing applications from requesting audio focus during a test,
+ * which could interfere with the testing of the functionality/behavior under test.
+ * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest}
+ * when the testing is done. If this is not the case (e.g. in case of a test crash),
+ * a death observer mechanism will ensure the system is not left in a bad state, but this should
+ * not be relied on when implementing tests.
+ * @see AudioManager#enterAudioFocusFreezeForTest(List)
+ * @param cb IBinder to track the death of the client of this method
+ * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance
+ * be those of the test runner and other players used in the test
+ * @return true if the focus freeze mode is successfully entered, false if there was an issue,
+ * such as another freeze currently used.
+ */
+ @Override
+ @EnforcePermission("android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ public boolean enterAudioFocusFreezeForTest(IBinder cb, int[] exemptedUids) {
+ super.enterAudioFocusFreezeForTest_enforcePermission();
+ Objects.requireNonNull(exemptedUids);
+ Objects.requireNonNull(cb);
+ return mMediaFocusControl.enterAudioFocusFreezeForTest(cb, exemptedUids);
+ }
+
+ /**
+ * Test method to end preventing applications from requesting audio focus during a test.
+ * @see AudioManager#exitAudioFocusFreezeForTest()
+ * @param cb IBinder identifying the client of this method
+ * @return true if the focus freeze mode is successfully exited, false if there was an issue,
+ * such as the freeze already having ended, or not started.
+ */
+ @Override
+ @EnforcePermission("android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ public boolean exitAudioFocusFreezeForTest(IBinder cb) {
+ super.exitAudioFocusFreezeForTest_enforcePermission();
+ Objects.requireNonNull(cb);
+ return mMediaFocusControl.exitAudioFocusFreezeForTest(cb);
+ }
+
/** only public for mocking/spying, do not call outside of AudioService */
@VisibleForTesting
public boolean hasAudioFocusUsers() {
@@ -10021,6 +10099,7 @@ public class AudioService extends IAudioService.Stub
}
/** see {@link AudioManager#getFadeOutDurationOnFocusLossMillis(AudioAttributes)} */
+ @Override
public long getFadeOutDurationOnFocusLossMillis(AudioAttributes aa) {
if (!enforceQueryAudioStateForTest("fade out duration")) {
return 0;
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 3560797ce2cf..b350363f32e1 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -329,7 +329,7 @@ public class BtHelper {
default:
break;
}
- if(broadcast) {
+ if (broadcast) {
broadcastScoConnectionState(scoAudioState);
//FIXME: this is to maintain compatibility with deprecated intent
// AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
@@ -459,6 +459,8 @@ public class BtHelper {
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void onBtProfileDisconnected(int profile) {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "BT profile " + BluetoothProfile.getProfileName(profile) + " disconnected"));
switch (profile) {
case BluetoothProfile.A2DP:
mA2dp = null;
@@ -487,6 +489,9 @@ public class BtHelper {
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "BT profile " + BluetoothProfile.getProfileName(profile) + " connected to proxy "
+ + proxy));
if (profile == BluetoothProfile.HEADSET) {
onHeadsetProfileConnected((BluetoothHeadset) proxy);
return;
@@ -718,8 +723,10 @@ public class BtHelper {
checkScoAudioState();
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
// Make sure that the state transitions to CONNECTING even if we cannot initiate
- // the connection.
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+ // the connection except if already connected internally
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL) {
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+ }
switch (mScoAudioState) {
case SCO_STATE_INACTIVE:
mScoAudioMode = scoAudioMode;
@@ -775,7 +782,7 @@ public class BtHelper {
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
break;
case SCO_STATE_ACTIVE_INTERNAL:
- Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
+ // Already in ACTIVE mode, simply return
break;
case SCO_STATE_ACTIVE_EXTERNAL:
/* Confirm SCO Audio connection to requesting app as it is already connected
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 88a4b0531cb1..010d5f41bc7d 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -43,7 +43,7 @@ import java.io.PrintWriter;
public class FocusRequester {
// on purpose not using this classe's name, as it will only be used from MediaFocusControl
- private static final String TAG = "MediaFocusControl";
+ private static final String TAG = "FocusRequester";
private static final boolean DEBUG = false;
private AudioFocusDeathHandler mDeathHandler; // may be null
@@ -340,6 +340,9 @@ public class FocusRequester {
@GuardedBy("MediaFocusControl.mAudioFocusLock")
boolean handleFocusLossFromGain(int focusGain, final FocusRequester frWinner, boolean forceDuck)
{
+ if (DEBUG) {
+ Log.i(TAG, "handleFocusLossFromGain for " + mClientId + " gain:" + focusGain);
+ }
final int focusLoss = focusLossForGainRequest(focusGain);
handleFocusLoss(focusLoss, frWinner, forceDuck);
return (focusLoss == AudioManager.AUDIOFOCUS_LOSS);
@@ -378,6 +381,9 @@ public class FocusRequester {
@GuardedBy("MediaFocusControl.mAudioFocusLock")
void handleFocusLoss(int focusLoss, @Nullable final FocusRequester frWinner, boolean forceDuck)
{
+ if (DEBUG) {
+ Log.i(TAG, "handleFocusLoss for " + mClientId + " loss:" + focusLoss);
+ }
try {
if (focusLoss != mFocusLossReceived) {
mFocusLossReceived = focusLoss;
@@ -427,6 +433,9 @@ public class FocusRequester {
toAudioFocusInfo(), true /* wasDispatched */);
mFocusLossWasNotified = true;
fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
+ } else if (DEBUG) {
+ Log.i(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
+ + " to " + mClientId + " no IAudioFocusDispatcher");
}
}
} catch (android.os.RemoteException e) {
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index b2180962a96e..65f6c9b8d459 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -45,6 +45,7 @@ import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
@@ -122,6 +123,23 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
dumpMultiAudioFocus(pw);
}
+ /**
+ * Test method to return the duration of the fade out applied on the players of a focus loser
+ * @return the fade out duration in ms
+ */
+ public long getFocusFadeOutDurationForTest() {
+ return FadeOutManager.FADE_OUT_DURATION_MS;
+ }
+
+ /**
+ * Test method to return the length of time after a fade out before the focus loser is unmuted
+ * (and is faded back in).
+ * @return the time gap after a fade out completion on focus loss, and fade in start in ms
+ */
+ public long getFocusUnmuteDelayAfterFadeOutForTest() {
+ return FadeOutManager.DELAY_FADE_IN_OFFENDERS_MS;
+ }
+
//=================================================================
// PlayerFocusEnforcer implementation
@Override
@@ -304,17 +322,26 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
@GuardedBy("mAudioFocusLock")
private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr,
boolean forceDuck) {
+ if (DEBUG) {
+ Log.i(TAG, "propagateFocusLossFromGain_syncAf gain:" + focusGain);
+ }
final List<String> clientsToRemove = new LinkedList<String>();
// going through the audio focus stack to signal new focus, traversing order doesn't
// matter as all entries respond to the same external focus gain
if (!mFocusStack.empty()) {
for (FocusRequester focusLoser : mFocusStack) {
+ if (DEBUG) {
+ Log.i(TAG, "propagateFocusLossFromGain_syncAf checking client:"
+ + focusLoser.getClientId());
+ }
final boolean isDefinitiveLoss =
focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);
if (isDefinitiveLoss) {
clientsToRemove.add(focusLoser.getClientId());
}
}
+ } else if (DEBUG) {
+ Log.i(TAG, "propagateFocusLossFromGain_syncAf empty stack");
}
if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {
@@ -370,6 +397,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
@GuardedBy("mAudioFocusLock")
private void removeFocusStackEntry(String clientToRemove, boolean signal,
boolean notifyFocusFollowers) {
+ if (DEBUG) {
+ Log.i(TAG, "removeFocusStackEntry client:" + clientToRemove);
+ }
AudioFocusInfo abandonSource = null;
// is the current top of the focus stack abandoning focus? (because of request, not death)
if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
@@ -1000,6 +1030,24 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
}
synchronized(mAudioFocusLock) {
+ // check whether a focus freeze is in place and filter
+ if (isFocusFrozenForTest()) {
+ int focusRequesterUid;
+ if ((flags & AudioManager.AUDIOFOCUS_FLAG_TEST)
+ == AudioManager.AUDIOFOCUS_FLAG_TEST) {
+ focusRequesterUid = testUid;
+ } else {
+ focusRequesterUid = Binder.getCallingUid();
+ }
+ if (isFocusFrozenForTestForUid(focusRequesterUid)) {
+ Log.i(TAG, "requestAudioFocus: focus frozen for test for uid:"
+ + focusRequesterUid);
+ return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+ }
+ Log.i(TAG, "requestAudioFocus: focus frozen for test but uid:" + focusRequesterUid
+ + " is exempt");
+ }
+
if (mFocusStack.size() > MAX_STACK_SIZE) {
Log.e(TAG, "Max AudioFocus stack size reached, failing requestAudioFocus()");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
@@ -1191,6 +1239,110 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
+ /**
+ * Reference to the caller of {@link #enterAudioFocusFreezeForTest(IBinder, int[])}
+ * Will be null when there is no focus freeze for test
+ */
+ @GuardedBy("mAudioFocusLock")
+ @Nullable
+ private IBinder mFocusFreezerForTest = null;
+
+ /**
+ * The death handler for {@link #mFocusFreezerForTest}
+ * Will be null when there is no focus freeze for test
+ */
+ @GuardedBy("mAudioFocusLock")
+ @Nullable
+ private IBinder.DeathRecipient mFocusFreezerDeathHandler = null;
+
+ /**
+ * Array of UIDs exempt from focus freeze when focus is frozen for test, null during normal
+ * operations.
+ * Will be null when there is no focus freeze for test
+ */
+ @GuardedBy("mAudioFocusLock")
+ @Nullable
+ private int[] mFocusFreezeExemptUids = null;
+
+ @GuardedBy("mAudioFocusLock")
+ private boolean isFocusFrozenForTest() {
+ return (mFocusFreezerForTest != null);
+ }
+
+ /**
+ * Checks if the given UID can request focus when a focus freeze is in place for a test.
+ * Focus can be requested if focus is not frozen or if it's frozen but the UID is exempt.
+ * @param uidToCheck
+ * @return true if that UID is barred from requesting focus, false if its focus request
+ * can proceed being processed
+ */
+ @GuardedBy("mAudioFocusLock")
+ private boolean isFocusFrozenForTestForUid(int uidToCheck) {
+ if (isFocusFrozenForTest()) {
+ return false;
+ }
+ // check the list of exempts (array is not null because we're in a freeze for test
+ for (int uid : mFocusFreezeExemptUids) {
+ if (uid == uidToCheck) {
+ return false;
+ }
+ }
+ // uid was not found in the exempt list, its focus request is denied
+ return true;
+ }
+
+ protected boolean enterAudioFocusFreezeForTest(
+ @NonNull IBinder cb, @NonNull int[] exemptedUids) {
+ Log.i(TAG, "enterAudioFocusFreezeForTest UIDs exempt:" + Arrays.toString(exemptedUids));
+ synchronized (mAudioFocusLock) {
+ if (mFocusFreezerForTest != null) {
+ Log.e(TAG, "Error enterAudioFocusFreezeForTest: focus already frozen");
+ return false;
+ }
+ // new focus freeze, register death handler
+ try {
+ mFocusFreezerDeathHandler = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.i(TAG, "Audio focus freezer died, exiting focus freeze for test");
+ releaseFocusFreeze();
+ }
+ };
+ cb.linkToDeath(mFocusFreezerDeathHandler, 0);
+ mFocusFreezerForTest = cb;
+ mFocusFreezeExemptUids = exemptedUids.clone();
+ } catch (RemoteException e) {
+ // client has already died!
+ mFocusFreezerForTest = null;
+ mFocusFreezeExemptUids = null;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected boolean exitAudioFocusFreezeForTest(@NonNull IBinder cb) {
+ synchronized (mAudioFocusLock) {
+ if (mFocusFreezerForTest != cb) {
+ Log.e(TAG, "Error exitAudioFocusFreezeForTest: "
+ + ((mFocusFreezerForTest == null)
+ ? "call to exit while not frozen"
+ : "call to exit not coming from freeze owner"));
+ return false;
+ }
+ mFocusFreezerForTest.unlinkToDeath(mFocusFreezerDeathHandler, 0);
+ releaseFocusFreeze();
+ }
+ return true;
+ }
+
+ private void releaseFocusFreeze() {
+ synchronized (mAudioFocusLock) {
+ mFocusFreezerDeathHandler = null;
+ mFocusFreezeExemptUids = null;
+ mFocusFreezerForTest = null;
+ }
+ }
protected void unregisterAudioFocusClient(String clientId) {
synchronized(mAudioFocusLock) {
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 23a0782dc8a3..54fa6fbc3bfd 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -1208,6 +1208,17 @@ public final class PlaybackActivityMonitor
}
}
+ protected @NonNull List<Integer> getFocusDuckedUids() {
+ final ArrayList<Integer> duckedUids;
+ synchronized (mPlayerLock) {
+ duckedUids = new ArrayList(mDuckingManager.mDuckers.keySet());
+ }
+ if (DEBUG) {
+ Log.i(TAG, "current ducked UIDs: " + duckedUids);
+ }
+ return duckedUids;
+ }
+
//=================================================================
// For logging
private static final class PlayerEvent extends EventLogger.Event {
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
index d238dae634ad..2ede56dcecd9 100644
--- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -67,7 +67,7 @@ class GestureMonitorSpyWindow {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
- t.setLayer(mInputSurface, Integer.MAX_VALUE);
+ t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_GESTURE_MONITOR);
t.setPosition(mInputSurface, 0, 0);
t.setCrop(mInputSurface, null /* crop to parent surface */);
t.show(mInputSurface);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index b8e9d5dfb3bc..62660c4f3c6d 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -381,6 +381,17 @@ public class InputManagerService extends IInputManager.Stub
public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
+ // The following are layer numbers used for z-ordering the input overlay layers on the display.
+ // This is used for ordering layers inside {@code DisplayContent#getInputOverlayLayer()}.
+ //
+ // The layer where gesture monitors are added.
+ public static final int INPUT_OVERLAY_LAYER_GESTURE_MONITOR = 1;
+ // Place the handwriting layer above gesture monitors so that styluses cannot trigger
+ // system gestures (e.g. navigation bar, edge-back, etc) while there is an active
+ // handwriting session.
+ public static final int INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE = 2;
+
+
private final String mVelocityTrackerStrategy;
/** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index 0c889c2765bb..7726f40fa2ae 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -27,16 +27,13 @@ import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import com.android.server.input.InputManagerService;
+
final class HandwritingEventReceiverSurface {
public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName();
static final boolean DEBUG = HandwritingModeController.DEBUG;
- // Place the layer at the highest layer so stylus cannot trigger gesture monitors
- // (e.g. navigation bar, edge-back, etc) while handwriting is ongoing.
- // TODO(b/217538817): Specify the ordering in WM by usage.
- private static final int HANDWRITING_SURFACE_LAYER = Integer.MAX_VALUE;
-
private final InputWindowHandle mWindowHandle;
private final InputChannel mClientChannel;
private final SurfaceControl mInputSurface;
@@ -68,7 +65,7 @@ final class HandwritingEventReceiverSurface {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
- t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
+ t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);
t.setPosition(mInputSurface, 0, 0);
t.setCrop(mInputSurface, null /* crop to parent surface */);
t.show(mInputSurface);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8e7baf26984a..1ec8b10813cd 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3275,15 +3275,18 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
} else {
// If subtype is null, try to find the most applicable one from
// getCurrentInputMethodSubtype.
+ subtypeId = NOT_A_SUBTYPE_ID;
newSubtype = getCurrentInputMethodSubtypeLocked();
+ if (newSubtype != null) {
+ for (int i = 0; i < subtypeCount; ++i) {
+ if (Objects.equals(newSubtype, info.getSubtypeAt(i))) {
+ subtypeId = i;
+ break;
+ }
+ }
+ }
}
- if (newSubtype == null || oldSubtype == null) {
- Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
- + ", new subtype = " + newSubtype);
- notifyInputMethodSubtypeChangedLocked(userId, info, null);
- return;
- }
- if (!newSubtype.equals(oldSubtype)) {
+ if (!Objects.equals(newSubtype, oldSubtype)) {
setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
IInputMethodInvoker curMethod = getCurMethodLocked();
if (curMethod != null) {
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 567d8ac5e5df..f21a9fe6af2a 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -201,10 +201,10 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
this::onProviderEnabledChanged;
private final SettingsHelper.GlobalSettingChangedListener
mBackgroundThrottlePackageWhitelistChangedListener =
- this::onBackgroundThrottlePackageWhitelistChanged;
+ this::onBackgroundThrottlePackageAllowlistChanged;
private final SettingsHelper.UserSettingChangedListener
mLocationPackageBlacklistChangedListener =
- this::onLocationPackageBlacklistChanged;
+ this::onLocationPackageDenylistChanged;
private final LocationPermissionsHelper.LocationPermissionsListener
mLocationPermissionsListener =
new LocationPermissionsHelper.LocationPermissionsListener() {
@@ -407,11 +407,11 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
}
- private void onBackgroundThrottlePackageWhitelistChanged() {
+ private void onBackgroundThrottlePackageAllowlistChanged() {
updateRegistrations(registration -> true);
}
- private void onLocationPackageBlacklistChanged(int userId) {
+ private void onLocationPackageDenylistChanged(int userId) {
updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
}
diff --git a/services/core/java/com/android/server/location/injector/SettingsHelper.java b/services/core/java/com/android/server/location/injector/SettingsHelper.java
index 490bfe1ab82f..32cbff8d50c7 100644
--- a/services/core/java/com/android/server/location/injector/SettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SettingsHelper.java
@@ -93,37 +93,37 @@ public abstract class SettingsHelper {
GlobalSettingChangedListener listener);
/**
- * Check if the given package is blacklisted for location access.
+ * Check if the given package is denylisted for location access.
*/
public abstract boolean isLocationPackageBlacklisted(int userId, String packageName);
/**
- * Add a listener for changes to the location package blacklist. Callbacks occur on an
+ * Add a listener for changes to the location package denylist. Callbacks occur on an
* unspecified thread.
*/
public abstract void addOnLocationPackageBlacklistChangedListener(
UserSettingChangedListener listener);
/**
- * Remove a listener for changes to the location package blacklist.
+ * Remove a listener for changes to the location package denylist.
*/
public abstract void removeOnLocationPackageBlacklistChangedListener(
UserSettingChangedListener listener);
/**
- * Retrieve the background throttle package whitelist.
+ * Retrieve the background throttle package allowlist.
*/
public abstract Set<String> getBackgroundThrottlePackageWhitelist();
/**
- * Add a listener for changes to the background throttle package whitelist. Callbacks occur on
+ * Add a listener for changes to the background throttle package allowlist. Callbacks occur on
* an unspecified thread.
*/
public abstract void addOnBackgroundThrottlePackageWhitelistChangedListener(
GlobalSettingChangedListener listener);
/**
- * Remove a listener for changes to the background throttle package whitelist.
+ * Remove a listener for changes to the background throttle package allowlist.
*/
public abstract void removeOnBackgroundThrottlePackageWhitelistChangedListener(
GlobalSettingChangedListener listener);
@@ -134,14 +134,14 @@ public abstract class SettingsHelper {
public abstract boolean isGnssMeasurementsFullTrackingEnabled();
/**
- * Add a listener for changes to the background throttle package whitelist. Callbacks occur on
+ * Add a listener for changes to the background throttle package allowlist. Callbacks occur on
* an unspecified thread.
*/
public abstract void addOnGnssMeasurementsFullTrackingEnabledChangedListener(
GlobalSettingChangedListener listener);
/**
- * Remove a listener for changes to the background throttle package whitelist.
+ * Remove a listener for changes to the background throttle package allowlist.
*/
public abstract void removeOnGnssMeasurementsFullTrackingEnabledChangedListener(
GlobalSettingChangedListener listener);
@@ -166,14 +166,14 @@ public abstract class SettingsHelper {
public abstract PackageTagsList getIgnoreSettingsAllowlist();
/**
- * Add a listener for changes to the ignore settings package whitelist. Callbacks occur on an
+ * Add a listener for changes to the ignore settings package allowlist. Callbacks occur on an
* unspecified thread.
*/
public abstract void addIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener);
/**
- * Remove a listener for changes to the ignore settings package whitelist.
+ * Remove a listener for changes to the ignore settings package allowlist.
*/
public abstract void removeIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener);
diff --git a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
index 777683ef59cf..8bb184c43ebb 100644
--- a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
@@ -65,8 +65,8 @@ import java.util.function.Supplier;
*/
public class SystemSettingsHelper extends SettingsHelper {
- private static final String LOCATION_PACKAGE_BLACKLIST = "locationPackagePrefixBlacklist";
- private static final String LOCATION_PACKAGE_WHITELIST = "locationPackagePrefixWhitelist";
+ private static final String LOCATION_PACKAGE_DENYLIST = "locationPackagePrefixBlacklist";
+ private static final String LOCATION_PACKAGE_ALLOWLIST = "locationPackagePrefixWhitelist";
private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
private static final long DEFAULT_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS =
@@ -93,9 +93,9 @@ public class SystemSettingsHelper extends SettingsHelper {
mGnssMeasurementFullTracking = new BooleanGlobalSetting(context,
ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, FgThread.getHandler());
mLocationPackageBlacklist = new StringListCachedSecureSetting(context,
- LOCATION_PACKAGE_BLACKLIST, FgThread.getHandler());
+ LOCATION_PACKAGE_DENYLIST, FgThread.getHandler());
mLocationPackageWhitelist = new StringListCachedSecureSetting(context,
- LOCATION_PACKAGE_WHITELIST, FgThread.getHandler());
+ LOCATION_PACKAGE_ALLOWLIST, FgThread.getHandler());
mBackgroundThrottlePackageWhitelist = new StringSetCachedGlobalSetting(context,
LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
() -> SystemConfig.getInstance().getAllowUnthrottledLocation(),
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index d700c6adfebb..8e9c21f5f35f 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -77,7 +77,6 @@ import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
-
/**
* A class that manages a user's synthetic password (SP) ({@link #SyntheticPassword}), along with a
* set of SP protectors that are independent ways that the SP is protected.
@@ -552,22 +551,48 @@ class SyntheticPasswordManager {
}
}
- private @Nullable IWeaver getWeaverServiceInternal() {
- // Try to get the AIDL service first
+ private @Nullable IWeaver getWeaverAidlService() {
+ final IWeaver aidlWeaver;
try {
- IWeaver aidlWeaver = IWeaver.Stub.asInterface(
- ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default"));
- if (aidlWeaver != null) {
- Slog.i(TAG, "Using AIDL weaver service");
- try {
- aidlWeaver.asBinder().linkToDeath(new WeaverDiedRecipient(), 0);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to register Weaver death recipient", e);
- }
- return aidlWeaver;
- }
+ aidlWeaver =
+ IWeaver.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default"));
} catch (SecurityException e) {
Slog.w(TAG, "Does not have permissions to get AIDL weaver service");
+ return null;
+ }
+ if (aidlWeaver == null) {
+ return null;
+ }
+ final int aidlVersion;
+ try {
+ aidlVersion = aidlWeaver.getInterfaceVersion();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Cannot get AIDL weaver service version", e);
+ return null;
+ }
+ if (aidlVersion < 2) {
+ Slog.w(TAG,
+ "Ignoring AIDL weaver service v"
+ + aidlVersion
+ + " because only v2 and later are supported");
+ return null;
+ }
+ Slog.i(TAG, "Found AIDL weaver service v" + aidlVersion);
+ return aidlWeaver;
+ }
+
+ private @Nullable IWeaver getWeaverServiceInternal() {
+ // Try to get the AIDL service first
+ IWeaver aidlWeaver = getWeaverAidlService();
+ if (aidlWeaver != null) {
+ Slog.i(TAG, "Using AIDL weaver service");
+ try {
+ aidlWeaver.asBinder().linkToDeath(new WeaverDiedRecipient(), 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to register Weaver death recipient", e);
+ }
+ return aidlWeaver;
}
// If the AIDL service can't be found, look for the HIDL service
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index e7bd68efd597..515c7fb09ab0 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -735,12 +735,9 @@ public final class MediaProjectionManagerService extends SystemService
}
@Override //Binder call
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void addCallback(final IMediaProjectionWatcherCallback callback) {
- if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
- + "projection callbacks");
- }
+ addCallback_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
MediaProjectionManagerService.this.addCallback(callback);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index dc8fcb077f61..85731651dd59 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -338,8 +338,8 @@ public class NetworkPolicyLogger {
return "App idle state of uid " + uid + ": " + idle;
}
- private static String getAppIdleWlChangedLog(int uid, boolean isWhitelisted) {
- return "App idle whitelist state of uid " + uid + ": " + isWhitelisted;
+ private static String getAppIdleWlChangedLog(int uid, boolean isAllowlisted) {
+ return "App idle whitelist state of uid " + uid + ": " + isAllowlisted;
}
private static String getParoleStateChanged(boolean paroleOn) {
@@ -519,14 +519,14 @@ public class NetworkPolicyLogger {
data.timeStamp = System.currentTimeMillis();
}
- public void appIdleWlChanged(int uid, boolean isWhitelisted) {
+ public void appIdleWlChanged(int uid, boolean isAllowlisted) {
final Data data = getNextSlot();
if (data == null) return;
data.reset();
data.type = EVENT_APP_IDLE_WL_CHANGED;
data.ifield1 = uid;
- data.bfield1 = isWhitelisted;
+ data.bfield1 = isAllowlisted;
data.timeStamp = System.currentTimeMillis();
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index fb9bc017be0b..46e7041b8898 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -365,7 +365,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String TAG_NETWORK_POLICY = "network-policy";
private static final String TAG_UID_POLICY = "uid-policy";
private static final String TAG_APP_POLICY = "app-policy";
- private static final String TAG_WHITELIST = "whitelist";
+ private static final String TAG_ALLOWLIST = "whitelist";
private static final String TAG_RESTRICT_BACKGROUND = "restrict-background";
private static final String TAG_REVOKED_RESTRICT_BACKGROUND = "revoked-restrict-background";
private static final String TAG_XML_UTILS_INT_ARRAY = "int-array";
@@ -859,7 +859,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
@GuardedBy("mUidRulesFirstLock")
- private void updatePowerSaveWhitelistUL() {
+ private void updatePowerSaveAllowlistUL() {
int[] whitelist = mPowerWhitelistManager.getWhitelistedAppIds(/* includingIdle */ false);
mPowerSaveWhitelistExceptIdleAppIds.clear();
for (int uid : whitelist) {
@@ -950,7 +950,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
- updatePowerSaveWhitelistUL();
+ updatePowerSaveAllowlistUL();
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@@ -1194,7 +1194,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public void onReceive(Context context, Intent intent) {
// on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
synchronized (mUidRulesFirstLock) {
- updatePowerSaveWhitelistUL();
+ updatePowerSaveAllowlistUL();
updateRulesForRestrictPowerUL();
updateRulesForAppIdleUL();
}
@@ -2684,7 +2684,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
}
- } else if (TAG_WHITELIST.equals(tag)) {
+ } else if (TAG_ALLOWLIST.equals(tag)) {
insideAllowlist = true;
} else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
final int uid = readIntAttribute(in, ATTR_UID);
@@ -2694,7 +2694,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mRestrictBackgroundAllowlistRevokedUids.put(uid, true);
}
} else if (type == END_TAG) {
- if (TAG_WHITELIST.equals(tag)) {
+ if (TAG_ALLOWLIST.equals(tag)) {
insideAllowlist = false;
}
@@ -2870,7 +2870,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
out.endTag(null, TAG_POLICY_LIST);
// write all allowlists
- out.startTag(null, TAG_WHITELIST);
+ out.startTag(null, TAG_ALLOWLIST);
// revoked restrict background allowlist
int size = mRestrictBackgroundAllowlistRevokedUids.size();
@@ -2881,7 +2881,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
}
- out.endTag(null, TAG_WHITELIST);
+ out.endTag(null, TAG_ALLOWLIST);
out.endDocument();
@@ -4395,7 +4395,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
void updateRulesForPowerSaveUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
try {
- updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
+ updateRulesForAllowlistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
mUidFirewallPowerSaveRules);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
@@ -4404,14 +4404,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
void updateRuleForRestrictPowerUL(int uid) {
- updateRulesForWhitelistedPowerSaveUL(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
+ updateRulesForAllowlistedPowerSaveUL(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
}
@GuardedBy("mUidRulesFirstLock")
void updateRulesForDeviceIdleUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForDeviceIdleUL");
try {
- updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
+ updateRulesForAllowlistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
mUidFirewallDozableRules);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
@@ -4420,26 +4420,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
void updateRuleForDeviceIdleUL(int uid) {
- updateRulesForWhitelistedPowerSaveUL(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
+ updateRulesForAllowlistedPowerSaveUL(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
}
// NOTE: since both fw_dozable and fw_powersave uses the same map
// (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method.
@GuardedBy("mUidRulesFirstLock")
- private void updateRulesForWhitelistedPowerSaveUL(boolean enabled, int chain,
+ private void updateRulesForAllowlistedPowerSaveUL(boolean enabled, int chain,
SparseIntArray rules) {
if (enabled) {
- // Sync the whitelists before enabling the chain. We don't care about the rules if
+ // Sync the allowlists before enabling the chain. We don't care about the rules if
// we are disabling the chain.
final SparseIntArray uidRules = rules;
uidRules.clear();
final List<UserInfo> users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui);
- updateRulesForWhitelistedAppIds(uidRules, mPowerSaveTempWhitelistAppIds, user.id);
- updateRulesForWhitelistedAppIds(uidRules, mPowerSaveWhitelistAppIds, user.id);
+ updateRulesForAllowlistedAppIds(uidRules, mPowerSaveTempWhitelistAppIds, user.id);
+ updateRulesForAllowlistedAppIds(uidRules, mPowerSaveWhitelistAppIds, user.id);
if (chain == FIREWALL_CHAIN_POWERSAVE) {
- updateRulesForWhitelistedAppIds(uidRules,
+ updateRulesForAllowlistedAppIds(uidRules,
mPowerSaveWhitelistExceptIdleAppIds, user.id);
}
}
@@ -4454,7 +4454,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private void updateRulesForWhitelistedAppIds(final SparseIntArray uidRules,
+ private void updateRulesForAllowlistedAppIds(final SparseIntArray uidRules,
final SparseBooleanArray whitelistedAppIds, int userId) {
for (int i = whitelistedAppIds.size() - 1; i >= 0; --i) {
if (whitelistedAppIds.valueAt(i)) {
@@ -4515,12 +4515,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* allowlisted.
*/
@GuardedBy("mUidRulesFirstLock")
- private boolean isWhitelistedFromPowerSaveUL(int uid, boolean deviceIdleMode) {
+ private boolean isAllowlistedFromPowerSaveUL(int uid, boolean deviceIdleMode) {
final int appId = UserHandle.getAppId(uid);
boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId)
|| mPowerSaveWhitelistAppIds.get(appId);
if (!deviceIdleMode) {
- isWhitelisted = isWhitelisted || isWhitelistedFromPowerSaveExceptIdleUL(uid);
+ isWhitelisted = isWhitelisted || isAllowlistedFromPowerSaveExceptIdleUL(uid);
}
return isWhitelisted;
}
@@ -4530,7 +4530,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* (eg: Battery Saver and app idle).
*/
@GuardedBy("mUidRulesFirstLock")
- private boolean isWhitelistedFromPowerSaveExceptIdleUL(int uid) {
+ private boolean isAllowlistedFromPowerSaveExceptIdleUL(int uid) {
final int appId = UserHandle.getAppId(uid);
return mPowerSaveWhitelistExceptIdleAppIds.get(appId);
}
@@ -4546,9 +4546,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// NOTE: since both fw_dozable and fw_powersave uses the same map
// (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method.
@GuardedBy("mUidRulesFirstLock")
- private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
+ private void updateRulesForAllowlistedPowerSaveUL(int uid, boolean enabled, int chain) {
if (enabled) {
- final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid,
+ final boolean isWhitelisted = isAllowlistedFromPowerSaveUL(uid,
chain == FIREWALL_CHAIN_DOZABLE);
if (isWhitelisted || isUidForegroundOnRestrictPowerUL(uid)) {
setUidFirewallRuleUL(chain, uid, FIREWALL_RULE_ALLOW);
@@ -4806,7 +4806,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
@GuardedBy("mUidRulesFirstLock")
- private void updateRulesForTempWhitelistChangeUL(int appId) {
+ private void updateRulesForTempAllowlistChangeUL(int appId) {
final List<UserInfo> users = mUserManager.getUsers();
final int numUsers = users.size();
for (int i = 0; i < numUsers; i++) {
@@ -5197,7 +5197,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isTop = isUidTop(uid);
- final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
+ final boolean isWhitelisted = isAllowlistedFromPowerSaveUL(uid, mDeviceIdleMode);
final int oldEffectiveBlockedReasons;
final int newEffectiveBlockedReasons;
@@ -5220,9 +5220,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
- newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
+ newAllowedReasons |= (isAllowlistedFromPowerSaveUL(uid, true)
? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
- newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
+ newAllowedReasons |= (isAllowlistedFromPowerSaveExceptIdleUL(uid)
? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
newAllowedReasons |= (uidBlockedState.allowedReasons
& ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
@@ -6137,7 +6137,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else {
mPowerSaveTempWhitelistAppIds.delete(appId);
}
- updateRulesForTempWhitelistChangeUL(appId);
+ updateRulesForTempAllowlistChangeUL(appId);
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 47bb8f009920..34c8a0d19e23 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -154,13 +154,13 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
}
switch(type) {
case "app-idle-whitelist":
- return listAppIdleWhitelist();
+ return listAppIdleAllowlist();
case "wifi-networks":
return listWifiNetworks();
case "restrict-background-whitelist":
- return listRestrictBackgroundWhitelist();
+ return listRestrictBackgroundAllowlist();
case "restrict-background-blacklist":
- return listRestrictBackgroundBlacklist();
+ return listRestrictBackgroundDenylist();
}
pw.println("Error: unknown list type '" + type + "'");
return -1;
@@ -175,11 +175,11 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
}
switch(type) {
case "restrict-background-whitelist":
- return addRestrictBackgroundWhitelist();
+ return addRestrictBackgroundAllowlist();
case "restrict-background-blacklist":
- return addRestrictBackgroundBlacklist();
+ return addRestrictBackgroundDenylist();
case "app-idle-whitelist":
- return addAppIdleWhitelist();
+ return addAppIdleAllowlist();
}
pw.println("Error: unknown add type '" + type + "'");
return -1;
@@ -194,11 +194,11 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
}
switch(type) {
case "restrict-background-whitelist":
- return removeRestrictBackgroundWhitelist();
+ return removeRestrictBackgroundAllowlist();
case "restrict-background-blacklist":
- return removeRestrictBackgroundBlacklist();
+ return removeRestrictBackgroundDenylist();
case "app-idle-whitelist":
- return removeAppIdleWhitelist();
+ return removeAppIdleAllowlist();
}
pw.println("Error: unknown remove type '" + type + "'");
return -1;
@@ -241,17 +241,17 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
return 0;
}
- private int listRestrictBackgroundWhitelist() throws RemoteException {
+ private int listRestrictBackgroundAllowlist() throws RemoteException {
return listUidPolicies("Restrict background whitelisted UIDs",
POLICY_ALLOW_METERED_BACKGROUND);
}
- private int listRestrictBackgroundBlacklist() throws RemoteException {
+ private int listRestrictBackgroundDenylist() throws RemoteException {
return listUidPolicies("Restrict background blacklisted UIDs",
POLICY_REJECT_METERED_BACKGROUND);
}
- private int listAppIdleWhitelist() throws RemoteException {
+ private int listAppIdleAllowlist() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final int[] uids = mInterface.getAppIdleWhitelist();
return listUidList("App Idle whitelisted UIDs", uids);
@@ -311,23 +311,23 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
return 0;
}
- private int addRestrictBackgroundWhitelist() throws RemoteException {
+ private int addRestrictBackgroundAllowlist() throws RemoteException {
return setUidPolicy(POLICY_ALLOW_METERED_BACKGROUND);
}
- private int removeRestrictBackgroundWhitelist() throws RemoteException {
+ private int removeRestrictBackgroundAllowlist() throws RemoteException {
return resetUidPolicy("not whitelisted", POLICY_ALLOW_METERED_BACKGROUND);
}
- private int addRestrictBackgroundBlacklist() throws RemoteException {
+ private int addRestrictBackgroundDenylist() throws RemoteException {
return setUidPolicy(POLICY_REJECT_METERED_BACKGROUND);
}
- private int removeRestrictBackgroundBlacklist() throws RemoteException {
+ private int removeRestrictBackgroundDenylist() throws RemoteException {
return resetUidPolicy("not blacklisted", POLICY_REJECT_METERED_BACKGROUND);
}
- private int setAppIdleWhitelist(boolean isWhitelisted) {
+ private int setAppIdleAllowlist(boolean isWhitelisted) {
final int uid = getUidFromNextArg();
if (uid < 0) {
return uid;
@@ -336,12 +336,12 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
return 0;
}
- private int addAppIdleWhitelist() throws RemoteException {
- return setAppIdleWhitelist(true);
+ private int addAppIdleAllowlist() throws RemoteException {
+ return setAppIdleAllowlist(true);
}
- private int removeAppIdleWhitelist() throws RemoteException {
- return setAppIdleWhitelist(false);
+ private int removeAppIdleAllowlist() throws RemoteException {
+ return setAppIdleAllowlist(false);
}
private int listWifiNetworks() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 009cc3b57594..6f0a4b48c09e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1928,6 +1928,7 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.onUserRemoved(userId);
mAssistants.onUserRemoved(userId);
mHistoryManager.onUserRemoved(userId);
+ mPreferencesHelper.syncChannelsBypassingDnd();
handleSavePolicyFile();
} else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
@@ -2379,6 +2380,7 @@ public class NotificationManagerService extends SystemService {
});
mPermissionHelper = permissionHelper;
mNotificationChannelLogger = channelLogger;
+ mUserProfiles.updateCache(getContext());
mPreferencesHelper = new PreferencesHelper(getContext(),
mPackageManagerClient,
mRankingHandler,
@@ -2387,6 +2389,7 @@ public class NotificationManagerService extends SystemService {
mPermissionManager,
mNotificationChannelLogger,
mAppOps,
+ mUserProfiles,
new SysUiStatsEvent.BuilderFactory(),
mShowReviewPermissionsNotification);
mRankingHelper = new RankingHelper(getContext(),
@@ -2442,8 +2445,6 @@ public class NotificationManagerService extends SystemService {
mZenModeHelper.initZenMode();
mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
- mUserProfiles.updateCache(getContext());
-
if (mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
telephonyManager.listen(new PhoneStateListener() {
@Override
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 3f799dc08a3f..0e37f101ce70 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -38,7 +38,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -53,7 +52,6 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.metrics.LogMaker;
import android.net.Uri;
-import android.os.Binder;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
@@ -114,7 +112,6 @@ public class PreferencesHelper implements RankingConfig {
private static final int XML_VERSION_REVIEW_PERMISSIONS_NOTIFICATION = 4;
@VisibleForTesting
static final int UNKNOWN_UID = UserHandle.USER_NULL;
- private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
@VisibleForTesting
static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 5000;
@@ -196,6 +193,7 @@ public class PreferencesHelper implements RankingConfig {
private final PermissionManager mPermissionManager;
private final NotificationChannelLogger mNotificationChannelLogger;
private final AppOpsManager mAppOps;
+ private final ManagedServices.UserProfiles mUserProfiles;
private SparseBooleanArray mBadgingEnabled;
private SparseBooleanArray mBubblesEnabled;
@@ -204,14 +202,12 @@ public class PreferencesHelper implements RankingConfig {
private boolean mIsMediaNotificationFilteringEnabled = DEFAULT_MEDIA_NOTIFICATION_FILTERING;
private boolean mCurrentUserHasChannelsBypassingDnd;
private boolean mHideSilentStatusBarIcons = DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS;
- private boolean mShowReviewPermissionsNotification;
-
- private boolean mAllowInvalidShortcuts = false;
+ private final boolean mShowReviewPermissionsNotification;
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager,
NotificationChannelLogger notificationChannelLogger,
- AppOpsManager appOpsManager,
+ AppOpsManager appOpsManager, ManagedServices.UserProfiles userProfiles,
SysUiStatsEvent.BuilderFactory statsEventBuilderFactory,
boolean showReviewPermissionsNotification) {
mContext = context;
@@ -222,6 +218,7 @@ public class PreferencesHelper implements RankingConfig {
mPm = pm;
mNotificationChannelLogger = notificationChannelLogger;
mAppOps = appOpsManager;
+ mUserProfiles = userProfiles;
mStatsEventBuilderFactory = statsEventBuilderFactory;
mShowReviewPermissionsNotification = showReviewPermissionsNotification;
@@ -435,7 +432,7 @@ public class PreferencesHelper implements RankingConfig {
channel.getConversationId() != null &&
channel.getConversationId().contains(
PLACEHOLDER_CONVERSATION_ID);
- return mAllowInvalidShortcuts || (!mAllowInvalidShortcuts && !isInvalidShortcutChannel);
+ return !isInvalidShortcutChannel;
}
private boolean isDeletionOk(NotificationChannel nc) {
@@ -1790,8 +1787,9 @@ public class PreferencesHelper implements RankingConfig {
* Syncs {@link #mCurrentUserHasChannelsBypassingDnd} with the current user's notification
* policy before updating. Must be called:
* <ul>
- * <li>On system init, after channels and DND configurations are loaded.</li>
- * <li>When the current user changes, after the corresponding DND config is loaded.</li>
+ * <li>On system init, after channels and DND configurations are loaded.
+ * <li>When the current user is switched, after the corresponding DND config is loaded.
+ * <li>If users are removed (the removed user could've been a profile of the current one).
* </ul>
*/
void syncChannelsBypassingDnd() {
@@ -1805,20 +1803,19 @@ public class PreferencesHelper implements RankingConfig {
/**
* Updates the user's NotificationPolicy based on whether the current userId has channels
* bypassing DND. It should be called whenever a channel is created, updated, or deleted, or
- * when the current user is switched.
+ * when the current user (or its profiles) change.
*/
private void updateCurrentUserHasChannelsBypassingDnd(int callingUid,
boolean fromSystemOrSystemUi) {
ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>();
- final int currentUserId = getCurrentUser();
+ final IntArray currentUserIds = mUserProfiles.getCurrentProfileIds();
synchronized (mPackagePreferences) {
final int numPackagePreferences = mPackagePreferences.size();
for (int i = 0; i < numPackagePreferences; i++) {
final PackagePreferences r = mPackagePreferences.valueAt(i);
- // Package isn't associated with the current userId
- if (currentUserId != UserHandle.getUserId(r.uid)) {
- continue;
+ if (!currentUserIds.contains(UserHandle.getUserId(r.uid))) {
+ continue; // Package isn't associated with any profile of the current userId.
}
for (NotificationChannel channel : r.channels.values()) {
@@ -1842,13 +1839,6 @@ public class PreferencesHelper implements RankingConfig {
}
}
- private int getCurrentUser() {
- final long identity = Binder.clearCallingIdentity();
- int currentUserId = ActivityManager.getCurrentUser();
- Binder.restoreCallingIdentity(identity);
- return currentUserId;
- }
-
private boolean channelIsLiveLocked(PackagePreferences pkgPref, NotificationChannel channel) {
// Channel is in a group that's blocked
if (isGroupBlocked(pkgPref.pkg, pkgPref.uid, channel.getGroup())) {
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index c0bc6d14cd04..1908e4dff234 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -5,4 +5,11 @@ flag {
namespace: "systemui"
description: "This flag controls removing expired notification bitmaps"
bug: "290381858"
-} \ No newline at end of file
+}
+
+flag {
+ name: "polite_notifications"
+ namespace: "systemui"
+ description: "This flag controls the polite notification feature"
+ bug: "270456865"
+}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index b5ec1366fec6..66a170397b84 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -459,8 +459,8 @@ final class DeletePackageHelper {
// Do not uninstall the APK if an app should be cached
boolean keepUninstalledPackage =
mPm.shouldKeepUninstalledPackageLPr(packageName);
- if (ps.isAnyInstalled(
- mUserManagerInternal.getUserIds()) || keepUninstalledPackage) {
+ if (ps.isInstalledOrHasDataOnAnyOtherUser(
+ mUserManagerInternal.getUserIds(), userId) || keepUninstalledPackage) {
// Other users still have this package installed, so all
// we need to do is clear this user's data and save that
// it is uninstalled.
@@ -555,6 +555,7 @@ final class DeletePackageHelper {
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
mAppDataHelper.destroyAppDataLIF(pkg, nextUserId,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+ ps.setCeDataInode(-1, nextUserId);
}
mAppDataHelper.clearKeystoreData(nextUserId, ps.getAppId());
preferredActivityHelper.clearPackagePreferredActivities(ps.getPackageName(),
@@ -615,7 +616,9 @@ final class DeletePackageHelper {
Slog.d(TAG, "Marking package:" + ps.getPackageName()
+ " uninstalled for user:" + nextUserId);
}
- ps.setUserState(nextUserId, 0, COMPONENT_ENABLED_STATE_DEFAULT,
+ ps.setUserState(nextUserId,
+ ps.getCeDataInode(nextUserId),
+ COMPONENT_ENABLED_STATE_DEFAULT,
false /*installed*/,
true /*stopped*/,
true /*notLaunched*/,
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index b4c40e6fd361..c47775192c42 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -280,6 +280,11 @@ final class InstantAppResolverConnection implements DeathRecipient {
} catch (NoSuchElementException ignore) { }
}
mRemoteInstance = null;
+
+ try {
+ mContext.unbindService(mServiceConnection);
+ } catch (Exception ignored) {
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6c0aeecbf68b..c63d8be0e806 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2892,13 +2892,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private void notifyPackageUseInternal(String packageName, int reason) {
long time = System.currentTimeMillis();
- synchronized (mLock) {
- final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
- if (pkgSetting == null) {
- return;
- }
- pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, time);
- }
+ this.commitPackageStateMutation(null, mutator -> {
+ final PackageStateWrite state = mutator.forPackage(packageName);
+ state.setLastPackageUsageTime(reason, time);
+ });
}
/*package*/ DexManager getDexManager() {
@@ -6681,9 +6678,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public void notifyPackageUse(String packageName, int reason) {
- synchronized (mLock) {
- PackageManagerService.this.notifyPackageUseInternal(packageName, reason);
- }
+ PackageManagerService.this.notifyPackageUseInternal(packageName, reason);
}
@Nullable
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 80d6ebbd90b3..2d58fe5a1678 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -34,11 +34,13 @@ import java.io.File;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Stream;
/**
* Metrics class for reporting stats to logging infrastructures like statsd
@@ -155,10 +157,27 @@ final class PackageMetrics {
private long getApksSize(File apkDir) {
// TODO(b/249294752): also count apk sizes for failed installs
final AtomicLong apksSize = new AtomicLong();
- try (Stream<Path> walkStream = Files.walk(apkDir.toPath())) {
- walkStream.filter(p -> p.toFile().isFile()
- && ApkLiteParseUtils.isApkFile(p.toFile())).forEach(
- f -> apksSize.addAndGet(f.toFile().length()));
+ try {
+ Files.walkFileTree(apkDir.toPath(), new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+ throws IOException {
+ if (dir.equals(apkDir.toPath())) {
+ return FileVisitResult.CONTINUE;
+ } else {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ throws IOException {
+ if (file.toFile().isFile() && ApkLiteParseUtils.isApkFile(file.toFile())) {
+ apksSize.addAndGet(file.toFile().length());
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
} catch (IOException e) {
// ignore
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 14693a67f2a5..7cac3e1b9842 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -809,9 +809,16 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
return changed;
}
- boolean isAnyInstalled(int[] users) {
- for (int user: users) {
- if (readUserState(user).isInstalled()) {
+ boolean isInstalledOrHasDataOnAnyOtherUser(int[] allUsers, int currentUser) {
+ for (int user: allUsers) {
+ if (user == currentUser) {
+ continue;
+ }
+ final PackageUserStateInternal userState = readUserState(user);
+ if (userState.isInstalled()) {
+ return true;
+ }
+ if (userState.getCeDataInode() > 0) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 7ed10a4df1db..160b2aa05c18 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -516,6 +516,13 @@ final class ResolveIntentHelper {
@PackageManager.ResolveInfoFlagsBits long flags, int userId) {
if (!mUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
+
+ // Only if the service query is coming from the system process,
+ // it should be allowed to match quarantined components
+ if (callingUid != Process.SYSTEM_UID) {
+ flags |= PackageManager.FILTER_OUT_QUARANTINED_COMPONENTS;
+ }
+
final String instantAppPkgName = computer.getInstantAppPackageName(callingUid);
flags = computer.updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b01a89e672be..789719527c8d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -72,6 +72,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
@@ -93,7 +94,6 @@ import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiFunction;
/**
* Manages all permissions and handles permissions related tasks.
@@ -233,11 +233,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (checkPermissionDelegate == null) {
- return mPermissionManagerServiceImpl.checkPermission(
- packageName, permissionName, userId);
+ return mPermissionManagerServiceImpl.checkPermission(packageName, permissionName,
+ deviceId, userId);
}
- return checkPermissionDelegate.checkPermission(packageName, permissionName, userId,
- mPermissionManagerServiceImpl::checkPermission);
+ return checkPermissionDelegate.checkPermission(packageName, permissionName,
+ deviceId, userId, mPermissionManagerServiceImpl::checkPermission);
}
@Override
@@ -254,10 +254,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (checkPermissionDelegate == null) {
- return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName);
+ return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName, deviceId);
}
return checkPermissionDelegate.checkUidPermission(uid, permissionName,
- mPermissionManagerServiceImpl::checkUidPermission);
+ deviceId, mPermissionManagerServiceImpl::checkUidPermission);
}
@Override
@@ -511,14 +511,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public int getPermissionFlags(String packageName, String permissionName, int deviceId,
int userId) {
return mPermissionManagerServiceImpl
- .getPermissionFlags(packageName, permissionName, userId);
+ .getPermissionFlags(packageName, permissionName, deviceId, userId);
}
@Override
public void updatePermissionFlags(String packageName, String permissionName, int flagMask,
int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
mPermissionManagerServiceImpl.updatePermissionFlags(packageName, permissionName, flagMask,
- flagValues, checkAdjustPolicyFlagPermission, userId);
+ flagValues, checkAdjustPolicyFlagPermission, deviceId, userId);
}
@Override
@@ -560,14 +560,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void grantRuntimePermission(String packageName, String permissionName, int deviceId,
int userId) {
- mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName, userId);
+ mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName,
+ deviceId, userId);
}
@Override
public void revokeRuntimePermission(String packageName, String permissionName, int deviceId,
int userId, String reason) {
mPermissionManagerServiceImpl.revokeRuntimePermission(packageName, permissionName,
- userId, reason);
+ deviceId, userId, reason);
}
@Override
@@ -580,14 +581,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int deviceId, int userId) {
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
- permissionName, userId);
+ permissionName, deviceId, userId);
}
@Override
public boolean isPermissionRevokedByPolicy(String packageName, String permissionName,
int deviceId, int userId) {
- return mPermissionManagerServiceImpl
- .isPermissionRevokedByPolicy(packageName, permissionName, userId);
+ return mPermissionManagerServiceImpl.isPermissionRevokedByPolicy(packageName,
+ permissionName, deviceId, userId);
}
@Override
@@ -868,6 +869,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @param packageName the name of the package to be checked
* @param permissionName the name of the permission to be checked
+ * @param deviceId The device ID
* @param userId the user ID
* @param superImpl the original implementation that can be delegated to
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
@@ -876,20 +878,21 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @see android.content.pm.PackageManager#checkPermission(String, String)
*/
int checkPermission(@NonNull String packageName, @NonNull String permissionName,
- @UserIdInt int userId,
- @NonNull TriFunction<String, String, Integer, Integer> superImpl);
+ int deviceId, @UserIdInt int userId,
+ @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl);
/**
* Check whether the given UID has been granted the specified permission.
*
* @param uid the UID to be checked
* @param permissionName the name of the permission to be checked
+ * @param deviceId The device ID
* @param superImpl the original implementation that can be delegated to
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
* the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise
*/
- int checkUidPermission(int uid, @NonNull String permissionName,
- BiFunction<Integer, String, Integer> superImpl);
+ int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
+ TriFunction<Integer, String, Integer, Integer> superImpl);
/**
* @return list of delegated permissions
@@ -918,31 +921,32 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public int checkPermission(@NonNull String packageName, @NonNull String permissionName,
- int userId, @NonNull TriFunction<String, String, Integer, Integer> superImpl) {
+ int deviceId, int userId,
+ @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl) {
if (mDelegatedPackageName.equals(packageName)
&& isDelegatedPermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply("com.android.shell", permissionName, userId);
+ return superImpl.apply("com.android.shell", permissionName, deviceId, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(packageName, permissionName, userId);
+ return superImpl.apply(packageName, permissionName, deviceId, userId);
}
@Override
- public int checkUidPermission(int uid, @NonNull String permissionName,
- @NonNull BiFunction<Integer, String, Integer> superImpl) {
+ public int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
+ @NonNull TriFunction<Integer, String, Integer, Integer> superImpl) {
if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(Process.SHELL_UID, permissionName);
+ return superImpl.apply(Process.SHELL_UID, permissionName, deviceId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(uid, permissionName);
+ return superImpl.apply(uid, permissionName, deviceId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 4353c5787d4b..6764e087ff04 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -681,7 +681,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public int getPermissionFlags(String packageName, String permName, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
final int callingUid = Binder.getCallingUid();
return getPermissionFlagsInternal(packageName, permName, callingUid, userId);
}
@@ -724,7 +724,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
final int callingUid = Binder.getCallingUid();
boolean overridePolicy = false;
@@ -908,8 +908,12 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
}
+ private int checkPermission(String pkgName, String permName, int userId) {
+ return checkPermission(pkgName, permName, Context.DEVICE_ID_DEFAULT, userId);
+ }
+
@Override
- public int checkPermission(String pkgName, String permName, int userId) {
+ public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}
@@ -975,8 +979,12 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
return true;
}
+ private int checkUidPermission(int uid, String permName) {
+ return checkUidPermission(uid, permName, Context.DEVICE_ID_DEFAULT);
+ }
+
@Override
- public int checkUidPermission(int uid, String permName) {
+ public int checkUidPermission(int uid, String permName, int deviceId) {
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
@@ -1295,7 +1303,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public void grantRuntimePermission(String packageName, String permName, final int userId) {
+ public void grantRuntimePermission(String packageName, String permName, int deviceId,
+ int userId) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
@@ -1468,11 +1477,11 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int userId,
- String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int deviceId,
+ int userId, String reason) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
- checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
+ checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY, deviceId)
== PackageManager.PERMISSION_GRANTED;
revokeRuntimePermissionInternal(packageName, permName, overridePolicy, callingUid, userId,
@@ -1859,7 +1868,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- @UserIdInt int userId) {
+ int deviceId, @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
@@ -1922,7 +1931,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ int userId) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -2059,8 +2069,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
continue;
}
boolean isSystemOrPolicyFixed = (getPermissionFlags(newPackage.getPackageName(),
- permInfo.name, userId) & (FLAG_PERMISSION_SYSTEM_FIXED
- | FLAG_PERMISSION_POLICY_FIXED)) != 0;
+ permInfo.name, Context.DEVICE_ID_DEFAULT, userId) & (
+ FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_POLICY_FIXED)) != 0;
if (isSystemOrPolicyFixed) {
continue;
}
@@ -2226,7 +2236,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
for (final int userId : userIds) {
final int permissionState = checkPermission(packageName, permName,
userId);
- final int flags = getPermissionFlags(packageName, permName, userId);
+ final int flags = getPermissionFlags(packageName, permName,
+ Context.DEVICE_ID_DEFAULT, userId);
final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_POLICY_FIXED
| FLAG_PERMISSION_GRANTED_BY_DEFAULT
@@ -5122,8 +5133,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@NonNull
@Override
- public Set<String> getGrantedPermissions(@NonNull String packageName,
- @UserIdInt int userId) {
+ public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
Objects.requireNonNull(packageName, "packageName");
Preconditions.checkArgumentNonNegative(userId, "userId");
return getGrantedPermissionsInternal(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 128f847715ab..2d824aa1ba13 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -25,7 +25,6 @@ import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.permission.IOnPermissionsChangeListener;
-import android.permission.PermissionManager;
import android.permission.PermissionManagerInternal;
import com.android.server.pm.pkg.AndroidPackage;
@@ -137,14 +136,16 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
void removePermission(String permName);
/**
- * Gets the state flags associated with a permission.
+ * Gets the permission state flags associated with a permission.
*
* @param packageName the package name for which to get the flags
* @param permName the permission for which to get the flags
+ * @param deviceId The device for which to get the flags
* @param userId the user for which to get permission flags
* @return the permission flags
*/
- int getPermissionFlags(String packageName, String permName, int userId);
+ int getPermissionFlags(String packageName, String permName, int deviceId,
+ @UserIdInt int userId);
/**
* Updates the flags associated with a permission by replacing the flags in the specified mask
@@ -154,10 +155,11 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
* @param permName The permission for which to update the flags
* @param flagMask The flags which to replace
* @param flagValues The flags with which to replace
+ * @param deviceId The device for which to update the permission flags
* @param userId The user for which to update the permission flags
*/
- void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int userId);
+ void updatePermissionFlags(String packageName, String permName, int flagMask, int flagValues,
+ boolean checkAdjustPolicyFlagPermission, int deviceId, @UserIdInt int userId);
/**
* Update the permission flags for all packages and runtime permissions of a user in order
@@ -291,11 +293,13 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
*
* @param packageName the package to which to grant the permission
* @param permName the permission name to grant
+ * @param deviceId the device for which to grant the permission
* @param userId the user for which to grant the permission
*
- * @see #revokeRuntimePermission(String, String, android.os.UserHandle, String)
+ * @see #revokeRuntimePermission(String, String, int, int, String)
*/
- void grantRuntimePermission(String packageName, String permName, int userId);
+ void grantRuntimePermission(String packageName, String permName, int deviceId,
+ @UserIdInt int userId);
/**
* Revoke a runtime permission that was previously granted by
@@ -310,13 +314,14 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
*
* @param packageName the package from which to revoke the permission
* @param permName the permission name to revoke
+ * @param deviceId the device for which to revoke the permission
* @param userId the user for which to revoke the permission
* @param reason the reason for the revoke, or {@code null} for unspecified
*
- * @see #grantRuntimePermission(String, String, android.os.UserHandle)
+ * @see #grantRuntimePermission(String, String, int, int)
*/
- void revokeRuntimePermission(String packageName, String permName, int userId,
- String reason);
+ void revokeRuntimePermission(String packageName, String permName, int deviceId,
+ @UserIdInt int userId, String reason);
/**
* Revoke the POST_NOTIFICATIONS permission, without killing the app. This method must ONLY BE
@@ -333,24 +338,29 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
* does not clearly communicate to the user what would be the benefit from grating this
* permission.
*
+ * @param packageName the package name
* @param permName a permission your app wants to request
+ * @param deviceId the device for which to check the permission
+ * @param userId the user for which to check the permission
* @return whether you can show permission rationale UI
*/
boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- @UserIdInt int userId);
+ int deviceId, @UserIdInt int userId);
/**
- * Checks whether a particular permissions has been revoked for a package by policy. Typically
+ * Checks whether a particular permission has been revoked for a package by policy. Typically,
* the device owner or the profile owner may apply such a policy. The user cannot grant policy
* revoked permissions, hence the only way for an app to get such a permission is by a policy
* change.
*
* @param packageName the name of the package you are checking against
* @param permName the name of the permission you are checking for
- *
+ * @param deviceId the device for which you are checking the permission
+ * @param userId the device for which you are checking the permission
* @return whether the permission is restricted by policy
*/
- boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId);
+ boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ @UserIdInt int userId);
/**
* Get set of permissions that have been split into more granular or dependent permissions.
@@ -373,14 +383,25 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
List<SplitPermissionInfoParcelable> getSplitPermissions();
/**
- * TODO:theianchen add doc describing this is the old checkPermissionImpl
+ * Check whether a permission is granted or not to a package.
+ *
+ * @param pkgName package name
+ * @param permName permission name
+ * @param deviceId device ID
+ * @param userId user ID
+ * @return permission result {@link PackageManager.PermissionResult}
*/
- int checkPermission(String pkgName, String permName, int userId);
+ int checkPermission(String pkgName, String permName, int deviceId, @UserIdInt int userId);
/**
- * TODO:theianchen add doc describing this is the old checkUidPermissionImpl
+ * Check whether a permission is granted or not to an UID.
+ *
+ * @param uid UID
+ * @param permName permission name
+ * @param deviceId device ID
+ * @return permission result {@link PackageManager.PermissionResult}
*/
- int checkUidPermission(int uid, String permName);
+ int checkUidPermission(int uid, String permName, int deviceId);
/**
* Get all the package names requesting app op permissions.
@@ -400,15 +421,11 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
@UserIdInt int userId);
/**
- * Reset the runtime permission state changes for a package.
+ * Reset the runtime permission state changes for a package for all devices.
*
* TODO(zhanghai): Turn this into package change callback?
- *
- * @param pkg the package
- * @param userId the user ID
*/
- void resetRuntimePermissions(@NonNull AndroidPackage pkg,
- @UserIdInt int userId);
+ void resetRuntimePermissions(@NonNull AndroidPackage pkg, @UserIdInt int userId);
/**
* Reset the runtime permission state changes for all packages in a user.
@@ -449,8 +466,8 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
/**
* Get all the permissions granted to a package.
*
- * @param packageName the name of the package
- * @param userId the user ID
+ * @param packageName package name
+ * @param userId user ID
* @return the names of the granted permissions
*/
@NonNull
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
index 7f98e2163178..dacb8c6890a0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
@@ -120,21 +120,21 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
}
@Override
- public int getPermissionFlags(String packageName, String permName, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
Log.i(LOG_TAG, "getPermissionFlags(packageName = " + packageName + ", permName = "
- + permName + ", userId = " + userId + ")");
- return mService.getPermissionFlags(packageName, permName, userId);
+ + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ return mService.getPermissionFlags(packageName, permName, deviceId, userId);
}
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
Log.i(LOG_TAG, "updatePermissionFlags(packageName = " + packageName + ", permName = "
+ permName + ", flagMask = " + flagMask + ", flagValues = " + flagValues
+ ", checkAdjustPolicyFlagPermission = " + checkAdjustPolicyFlagPermission
- + ", userId = " + userId + ")");
+ + ", deviceId = " + deviceId + ", userId = " + userId + ")");
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
}
@Override
@@ -182,18 +182,20 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int userId) {
+ public void grantRuntimePermission(String packageName, String permName, int deviceId,
+ int userId) {
Log.i(LOG_TAG, "grantRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", userId = " + userId + ")");
- mService.grantRuntimePermission(packageName, permName, userId);
+ + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ mService.grantRuntimePermission(packageName, permName, deviceId, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int userId,
- String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int deviceId,
+ int userId, String reason) {
Log.i(LOG_TAG, "revokeRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", userId = " + userId + ", reason = " + reason + ")");
- mService.revokeRuntimePermission(packageName, permName, userId, reason);
+ + permName + ", deviceId = " + deviceId + ", userId = " + userId
+ + ", reason = " + reason + ")");
+ mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
}
@Override
@@ -205,17 +207,20 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int userId) {
+ int deviceId, int userId) {
Log.i(LOG_TAG, "shouldShowRequestPermissionRationale(packageName = " + packageName
- + ", permName = " + permName + ", userId = " + userId + ")");
- return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
+ + ", permName = " + permName + ", deviceId = " + deviceId
+ + ", userId = " + userId + ")");
+ return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
+ userId);
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ int userId) {
Log.i(LOG_TAG, "isPermissionRevokedByPolicy(packageName = " + packageName + ", permName = "
- + permName + ", userId = " + userId + ")");
- return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
+ + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
}
@Override
@@ -225,16 +230,17 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
}
@Override
- public int checkPermission(String pkgName, String permName, int userId) {
+ public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
Log.i(LOG_TAG, "checkPermission(pkgName = " + pkgName + ", permName = " + permName
- + ", userId = " + userId + ")");
- return mService.checkPermission(pkgName, permName, userId);
+ + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ return mService.checkPermission(pkgName, permName, deviceId, userId);
}
@Override
- public int checkUidPermission(int uid, String permName) {
- Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName + ")");
- return mService.checkUidPermission(uid, permName);
+ public int checkUidPermission(int uid, String permName, int deviceId) {
+ Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName
+ + ", deviceId = " + deviceId + ")");
+ return mService.checkUidPermission(uid, permName, deviceId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
index d4c6d42deeaa..35d165b9b54a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
@@ -153,9 +153,10 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public int getPermissionFlags(String packageName, String permName, int userId) {
- int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, userId);
- int newVal = mNewImplementation.getPermissionFlags(packageName, permName, userId);
+ public int getPermissionFlags(String packageName, String permName, int deviceId,
+ @UserIdInt int userId) {
+ int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
+ int newVal = mNewImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("getPermissionFlags");
@@ -165,11 +166,12 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId,
+ @UserIdInt int userId) {
mOldImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
mNewImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
}
@Override
@@ -234,16 +236,17 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int userId) {
- mOldImplementation.grantRuntimePermission(packageName, permName, userId);
- mNewImplementation.grantRuntimePermission(packageName, permName, userId);
+ public void grantRuntimePermission(String packageName, String permName, int deviceId,
+ @UserIdInt int userId) {
+ mOldImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
+ mNewImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int userId,
- String reason) {
- mOldImplementation.grantRuntimePermission(packageName, permName, userId);
- mNewImplementation.grantRuntimePermission(packageName, permName, userId);
+ public void revokeRuntimePermission(String packageName, String permName, int deviceId,
+ @UserIdInt int userId, String reason) {
+ mOldImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ mNewImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
}
@Override
@@ -255,11 +258,11 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int userId) {
- boolean oldVal = mOldImplementation
- .shouldShowRequestPermissionRationale(packageName, permName, userId);
- boolean newVal = mNewImplementation
- .shouldShowRequestPermissionRationale(packageName, permName, userId);
+ int deviceId, @UserIdInt int userId) {
+ boolean oldVal = mOldImplementation.shouldShowRequestPermissionRationale(packageName,
+ permName, deviceId, userId);
+ boolean newVal = mNewImplementation.shouldShowRequestPermissionRationale(packageName,
+ permName, deviceId, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("shouldShowRequestPermissionRationale");
@@ -268,11 +271,12 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
- boolean oldVal = mOldImplementation
- .isPermissionRevokedByPolicy(packageName, permName, userId);
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ @UserIdInt int userId) {
+ boolean oldVal = mOldImplementation.isPermissionRevokedByPolicy(packageName, permName,
+ deviceId, userId);
boolean newVal = mNewImplementation.isPermissionRevokedByPolicy(packageName, permName,
- userId);
+ deviceId, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("isPermissionRevokedByPolicy");
@@ -292,9 +296,9 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public int checkPermission(String pkgName, String permName, int userId) {
- int oldVal = mOldImplementation.checkPermission(pkgName, permName, userId);
- int newVal = mNewImplementation.checkPermission(pkgName, permName, userId);
+ public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+ int oldVal = mOldImplementation.checkPermission(pkgName, permName, deviceId, userId);
+ int newVal = mNewImplementation.checkPermission(pkgName, permName, deviceId, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("checkPermission");
@@ -303,9 +307,9 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public int checkUidPermission(int uid, String permName) {
- int oldVal = mOldImplementation.checkUidPermission(uid, permName);
- int newVal = mNewImplementation.checkUidPermission(uid, permName);
+ public int checkUidPermission(int uid, String permName, int deviceId) {
+ int oldVal = mOldImplementation.checkUidPermission(uid, permName, deviceId);
+ int newVal = mNewImplementation.checkUidPermission(uid, permName, deviceId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("checkUidPermission");
@@ -372,7 +376,7 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
@NonNull
@Override
- public Set<String> getGrantedPermissions(@NonNull String packageName, int userId) {
+ public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
Set<String> oldVal = mOldImplementation.getGrantedPermissions(packageName, userId);
Set<String> newVal = mNewImplementation.getGrantedPermissions(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
index 4e72fae99c9c..cbeede0f425c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -158,10 +158,10 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
}
@Override
- public int getPermissionFlags(String packageName, String permName, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionFlags");
try {
- return mService.getPermissionFlags(packageName, permName, userId);
+ return mService.getPermissionFlags(packageName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -169,12 +169,12 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#updatePermissionFlags");
try {
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -253,23 +253,24 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int userId) {
+ public void grantRuntimePermission(String packageName, String permName, int deviceId,
+ int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#grantRuntimePermission");
try {
- mService.grantRuntimePermission(packageName, permName, userId);
+ mService.grantRuntimePermission(packageName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int userId,
- String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int deviceId,
+ int userId, String reason) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#revokeRuntimePermission");
try {
- mService.revokeRuntimePermission(packageName, permName, userId, reason);
+ mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -288,22 +289,24 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int userId) {
+ int deviceId, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#shouldShowRequestPermissionRationale");
try {
- return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
+ return mService.shouldShowRequestPermissionRationale(
+ packageName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#isPermissionRevokedByPolicy");
try {
- return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
+ return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -321,20 +324,20 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
}
@Override
- public int checkPermission(String pkgName, String permName, int userId) {
+ public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkPermission");
try {
- return mService.checkPermission(pkgName, permName, userId);
+ return mService.checkPermission(pkgName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public int checkUidPermission(int uid, String permName) {
+ public int checkUidPermission(int uid, String permName, int deviceId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkUidPermission");
try {
- return mService.checkUidPermission(uid, permName);
+ return mService.checkUidPermission(uid, permName, deviceId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
diff --git a/services/core/java/com/android/server/pm/pkg/SuspendParams.java b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
index 153238fa6866..4e08106ed49a 100644
--- a/services/core/java/com/android/server/pm/pkg/SuspendParams.java
+++ b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
@@ -24,6 +24,7 @@ import android.util.Slog;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.pm.Flags;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -141,7 +142,8 @@ public final class SuspendParams {
PersistableBundle readAppExtras = null;
PersistableBundle readLauncherExtras = null;
- final boolean quarantined = in.getAttributeBoolean(null, ATTR_QUARANTINED, false);
+ final boolean quarantined = in.getAttributeBoolean(null, ATTR_QUARANTINED, false)
+ && Flags.quarantinedEnabled();
final int currentDepth = in.getDepth();
int type;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index e2cb87e72c7a..dc022f70e47c 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -3055,7 +3055,7 @@ public class ParsingPackageUtils {
*
* TODO(b/155513789): Remove this in favor of collecting certificates during the original parse
* call if requested. Leaving this as an optional method for the caller means we have to
- * construct a dummy ParseInput.
+ * construct a placeholder ParseInput.
*/
@CheckResult
public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index faf132e0d80d..b3aa09b8f17b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -29,6 +29,7 @@ import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.O;
+import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -208,7 +209,6 @@ import com.android.internal.policy.LogDecelerateInterpolator;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.AccessibilityManagerInternal;
import com.android.server.ExtconStateObserver;
@@ -339,6 +339,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS
static final int SHORT_PRESS_PRIMARY_NOTHING = 0;
static final int SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS = 1;
+ static final int SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY = 2;
// Must match: config_longPressOnStemPrimaryBehavior in config.xml
// The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS
@@ -610,6 +611,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// What we do when the user double-taps on home
private int mDoubleTapOnHomeBehavior;
+ // Must match config_primaryShortPressTargetActivity in config.xml
+ ComponentName mPrimaryShortPressTargetActivity;
+
// Whether to lock the device after the next dreaming transition has finished.
private boolean mLockAfterDreamingTransitionFinished;
@@ -622,9 +626,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mAllowTheaterModeWakeFromLidSwitch;
private boolean mAllowTheaterModeWakeFromWakeGesture;
- // Whether to support long press from power button in non-interactive mode
+ // If true, the power button long press behavior will be invoked even if the default display is
+ // non-interactive. If false, the power button long press behavior will be skipped if the
+ // default display is non-interactive.
private boolean mSupportLongPressPowerWhenNonInteractive;
+ // If true, the power button short press behavior will be always invoked as long as the default
+ // display is on, even if the display is not interactive. If false, the power button short press
+ // behavior will be skipped if the default display is non-interactive.
+ private boolean mSupportShortPressPowerWhenDefaultDisplayOn;
+
// Whether to go to sleep entering theater mode from power button
private boolean mGoToSleepOnButtonPressTheaterMode;
@@ -1041,7 +1052,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private void powerPress(long eventTime, int count, boolean beganFromNonInteractive) {
+ private void powerPress(long eventTime, int count) {
// SideFPS still needs to know about suppressed power buttons, in case it needs to block
// an auth attempt.
if (count == 1) {
@@ -1055,9 +1066,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final boolean interactive = mDefaultDisplayPolicy.isAwake();
- Slog.d(TAG, "powerPress: eventTime=" + eventTime + " interactive=" + interactive
- + " count=" + count + " beganFromNonInteractive=" + beganFromNonInteractive
- + " mShortPressOnPowerBehavior=" + mShortPressOnPowerBehavior);
+ Slog.d(
+ TAG,
+ "powerPress: eventTime="
+ + eventTime
+ + " interactive="
+ + interactive
+ + " count="
+ + count
+ + " mShortPressOnPowerBehavior="
+ + mShortPressOnPowerBehavior);
if (count == 2) {
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
@@ -1065,12 +1083,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (count > 3 && count <= getMaxMultiPressPowerCount()) {
Slog.d(TAG, "No behavior defined for power press count " + count);
- } else if (count == 1 && interactive && !beganFromNonInteractive) {
- if (mSideFpsEventHandler.shouldConsumeSinglePress(eventTime)) {
- Slog.i(TAG, "Suppressing power key because the user is interacting with the "
- + "fingerprint sensor");
- return;
- }
+ } else if (count == 1 && shouldHandleShortPressPowerAction(interactive, eventTime)) {
switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING:
break;
@@ -1118,6 +1131,44 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private boolean shouldHandleShortPressPowerAction(boolean interactive, long eventTime) {
+ if (mSupportShortPressPowerWhenDefaultDisplayOn) {
+ final boolean defaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+ final boolean beganFromDefaultDisplayOn =
+ mSingleKeyGestureDetector.beganFromDefaultDisplayOn();
+ if (!defaultDisplayOn || !beganFromDefaultDisplayOn) {
+ Slog.v(
+ TAG,
+ "Ignoring short press of power button because the default display is not"
+ + " on. defaultDisplayOn="
+ + defaultDisplayOn
+ + ", beganFromDefaultDisplayOn="
+ + beganFromDefaultDisplayOn);
+ return false;
+ }
+ return true;
+ }
+ final boolean beganFromNonInteractive = mSingleKeyGestureDetector.beganFromNonInteractive();
+ if (!interactive || beganFromNonInteractive) {
+ Slog.v(
+ TAG,
+ "Ignoring short press of power button because the device is not interactive."
+ + " interactive="
+ + interactive
+ + ", beganFromNonInteractive="
+ + beganFromNonInteractive);
+ return false;
+ }
+ if (mSideFpsEventHandler.shouldConsumeSinglePress(eventTime)) {
+ Slog.i(
+ TAG,
+ "Suppressing power key because the user is interacting with the "
+ + "fingerprint sensor");
+ return false;
+ }
+ return true;
+ }
+
/**
* Attempt to dream from a power button press.
*
@@ -1328,7 +1379,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerKeyHandled = true;
performHapticFeedback(HapticFeedbackConstants.ASSISTANT_BUTTON, false,
"Power - Long Press - Go To Assistant");
- final int powerKeyDeviceId = Integer.MIN_VALUE;
+ final int powerKeyDeviceId = INVALID_INPUT_DEVICE_ID;
launchAssistAction(null, powerKeyDeviceId, eventTime,
AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
break;
@@ -1415,23 +1466,59 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void stemPrimarySinglePressAction(int behavior) {
+ if (DEBUG_INPUT) {
+ Slog.d(TAG, "stemPrimarySinglePressAction: behavior=" + behavior);
+ }
+ if (behavior == SHORT_PRESS_PRIMARY_NOTHING) return;
+
+ final boolean keyguardActive = mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
+ if (keyguardActive) {
+ // If keyguarded then notify the keyguard.
+ mKeyguardDelegate.onSystemKeyPressed(KeyEvent.KEYCODE_STEM_PRIMARY);
+ return;
+ }
switch (behavior) {
- case SHORT_PRESS_PRIMARY_NOTHING:
- break;
case SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS:
if (DEBUG_INPUT) {
Slog.d(TAG, "Executing stem primary short press action behavior.");
}
- final boolean keyguardActive =
- mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
- if (!keyguardActive) {
- Intent intent = new Intent(Intent.ACTION_ALL_APPS);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS);
+ allAppsIntent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ startActivityAsUser(allAppsIntent, UserHandle.CURRENT_OR_SELF);
+ break;
+ case SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY:
+ if (DEBUG_INPUT) {
+ Slog.d(
+ TAG,
+ "Executing stem primary short press action behavior for launching "
+ + "target activity.");
+ }
+ if (mPrimaryShortPressTargetActivity != null) {
+ Intent targetActivityIntent = new Intent();
+ targetActivityIntent.setComponent(mPrimaryShortPressTargetActivity);
+ ResolveInfo resolveInfo =
+ mContext.getPackageManager()
+ .resolveActivity(targetActivityIntent, /* flags= */ 0);
+ if (resolveInfo != null) {
+ targetActivityIntent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+ startActivityAsUser(targetActivityIntent, UserHandle.CURRENT_OR_SELF);
+ } else {
+ Slog.wtf(
+ TAG,
+ "Could not resolve activity with : "
+ + mPrimaryShortPressTargetActivity.flattenToString()
+ + " name.");
+ }
} else {
- // If keyguarded then notify the keyguard.
- mKeyguardDelegate.onSystemKeyPressed(KeyEvent.KEYCODE_STEM_PRIMARY);
+ Slog.wtf(
+ TAG,
+ "mPrimaryShortPressTargetActivity must not be null and correctly"
+ + " specified");
}
break;
}
@@ -1481,7 +1568,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private void stemPrimaryLongPress() {
+ private void stemPrimaryLongPress(long eventTime) {
if (DEBUG_INPUT) {
Slog.d(TAG, "Executing stem primary long press action behavior.");
}
@@ -1490,7 +1577,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case LONG_PRESS_PRIMARY_NOTHING:
break;
case LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT:
- launchVoiceAssist(/* allowDuringSetup= */false);
+ final int stemPrimaryKeyDeviceId = INVALID_INPUT_DEVICE_ID;
+ launchAssistAction(
+ null,
+ stemPrimaryKeyDeviceId,
+ eventTime,
+ AssistUtils.INVOCATION_TYPE_UNKNOWN);
break;
}
}
@@ -2113,6 +2205,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mSensorPrivacyManager = mContext.getSystemService(SensorPrivacyManager.class);
+ mSearchManager = mContext.getSystemService(SearchManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -2231,6 +2324,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mSupportLongPressPowerWhenNonInteractive = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_supportLongPressPowerWhenNonInteractive);
+ mSupportShortPressPowerWhenDefaultDisplayOn =
+ mContext.getResources()
+ .getBoolean(
+ com.android.internal.R.bool
+ .config_supportShortPressPowerWhenDefaultDisplayOn);
mLongPressOnBackBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnBackBehavior);
@@ -2244,6 +2342,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerDoublePressTargetActivity = ComponentName.unflattenFromString(
mContext.getResources().getString(
com.android.internal.R.string.config_doublePressOnPowerTargetActivity));
+ mPrimaryShortPressTargetActivity = ComponentName.unflattenFromString(
+ mContext.getResources().getString(
+ com.android.internal.R.string.config_primaryShortPressTargetActivity));
mShortPressOnSleepBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnSleepBehavior);
mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
@@ -2518,8 +2619,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
void onPress(long downTime) {
- powerPress(downTime, 1 /*count*/,
- mSingleKeyGestureDetector.beganFromNonInteractive());
+ powerPress(downTime, 1 /*count*/);
}
@Override
@@ -2550,7 +2650,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
void onMultiPress(long downTime, int count) {
- powerPress(downTime, count, mSingleKeyGestureDetector.beganFromNonInteractive());
+ powerPress(downTime, count);
}
}
@@ -2608,7 +2708,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
void onLongPress(long eventTime) {
- stemPrimaryLongPress();
+ stemPrimaryLongPress(eventTime);
}
@Override
@@ -3855,7 +3955,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Add Intent Extra data.
Bundle args = null;
args = new Bundle();
- if (deviceId > Integer.MIN_VALUE) {
+ if (deviceId != INVALID_INPUT_DEVICE_ID) {
args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, deviceId);
}
if (hint != null) {
@@ -3864,8 +3964,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
args.putLong(Intent.EXTRA_TIME, eventTime);
args.putInt(AssistUtils.INVOCATION_TYPE_KEY, invocationType);
- ((SearchManager) mContext.createContextAsUser(UserHandle.of(mCurrentUserId), 0)
- .getSystemService(Context.SEARCH_SERVICE)).launchAssist(args);
+ if (mSearchManager != null) {
+ mSearchManager.launchAssist(args);
+ } else {
+ // Fallback to status bar if search manager doesn't exist (e.g. on wear).
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.startAssist(args);
+ }
+ }
}
/**
@@ -3876,39 +3983,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final boolean keyguardActive =
mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
if (!keyguardActive) {
- if (mHasFeatureWatch && isInRetailMode()) {
- launchRetailVoiceAssist(allowDuringSetup);
- } else {
- startVoiceAssistIntent(allowDuringSetup);
- }
- } else {
- mKeyguardDelegate.dismissKeyguardToLaunch(new Intent(Intent.ACTION_VOICE_ASSIST));
- }
- }
-
- private void launchRetailVoiceAssist(boolean allowDuringSetup) {
- Intent retailIntent = new Intent(ACTION_VOICE_ASSIST_RETAIL);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
- retailIntent, /* flags= */0);
- if (resolveInfo != null) {
- retailIntent.setComponent(
- new ComponentName(resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name));
- startActivityAsUser(retailIntent, null, UserHandle.CURRENT_OR_SELF,
+ startActivityAsUser(
+ new Intent(Intent.ACTION_VOICE_ASSIST),
+ /* bundle= */ null,
+ UserHandle.CURRENT_OR_SELF,
allowDuringSetup);
} else {
- Slog.w(TAG, "Couldn't find an app to process " + ACTION_VOICE_ASSIST_RETAIL
- + ". Fall back to start " + Intent.ACTION_VOICE_ASSIST);
- startVoiceAssistIntent(allowDuringSetup);
+ mKeyguardDelegate.dismissKeyguardToLaunch(new Intent(Intent.ACTION_VOICE_ASSIST));
}
}
- private void startVoiceAssistIntent(boolean allowDuringSetup) {
- Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
- startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF,
- allowDuringSetup);
- }
-
private boolean isInRetailMode() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_DEMO_MODE, 0) == 1;
@@ -3931,13 +4015,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private SearchManager getSearchManager() {
- if (mSearchManager == null) {
- mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
- }
- return mSearchManager;
- }
-
private void preloadRecentApps() {
mPreloadedRecentApps = true;
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
@@ -4323,10 +4400,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// This could prevent some wrong state in multi-displays environment,
// the default display may turned off but interactive is true.
- final boolean isDefaultDisplayOn = mDefaultDisplayPolicy.isAwake();
- final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
+ final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+ final boolean isDefaultDisplayAwake = mDefaultDisplayPolicy.isAwake();
+ final boolean interactiveAndAwake = interactive && isDefaultDisplayAwake;
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
- handleKeyGesture(event, interactiveAndOn);
+ handleKeyGesture(event, interactiveAndAwake, isDefaultDisplayOn);
}
// Enable haptics if down and virtual key without multiple repetitions. If this is a hard
@@ -4479,7 +4557,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
- interceptPowerKeyDown(event, interactiveAndOn);
+ interceptPowerKeyDown(event, interactiveAndAwake);
} else {
interceptPowerKeyUp(event, canceled);
}
@@ -4695,7 +4773,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return result;
}
- private void handleKeyGesture(KeyEvent event, boolean interactive) {
+ private void handleKeyGesture(KeyEvent event, boolean interactive, boolean defaultDisplayOn) {
if (mKeyCombinationManager.interceptKey(event, interactive)) {
// handled by combo keys manager.
mSingleKeyGestureDetector.reset();
@@ -4711,7 +4789,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- mSingleKeyGestureDetector.interceptKey(event, interactive);
+ mSingleKeyGestureDetector.interceptKey(event, interactive, defaultDisplayOn);
}
// The camera gesture will be detected by GestureLauncherService.
@@ -6167,6 +6245,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.print("mTriplePressOnPowerBehavior=");
pw.println(multiPressOnPowerBehaviorToString(mTriplePressOnPowerBehavior));
pw.print(prefix);
+ pw.print("mSupportShortPressPowerWhenDefaultDisplayOn=");
+ pw.println(mSupportShortPressPowerWhenDefaultDisplayOn);
+ pw.print(prefix);
pw.print("mPowerVolUpBehavior=");
pw.println(powerVolumeUpBehaviorToString(mPowerVolUpBehavior));
pw.print(prefix);
@@ -6417,6 +6498,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return "SHORT_PRESS_PRIMARY_NOTHING";
case SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS:
return "SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS";
+ case SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY:
+ return "SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY";
default:
return Integer.toString(behavior);
}
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index b999bbb3dce2..5fc0637debea 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -43,6 +43,7 @@ public final class SingleKeyGestureDetector {
private int mKeyPressCounter;
private boolean mBeganFromNonInteractive = false;
+ private boolean mBeganFromDefaultDisplayOn = false;
private final ArrayList<SingleKeyRule> mRules = new ArrayList();
private SingleKeyRule mActiveRule = null;
@@ -194,11 +195,12 @@ public final class SingleKeyGestureDetector {
mRules.remove(rule);
}
- void interceptKey(KeyEvent event, boolean interactive) {
+ void interceptKey(KeyEvent event, boolean interactive, boolean defaultDisplayOn) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
- // Store the non interactive state when first down.
+ // Store the non interactive state and display on state when first down.
if (mDownKeyCode == KeyEvent.KEYCODE_UNKNOWN || mDownKeyCode != event.getKeyCode()) {
mBeganFromNonInteractive = !interactive;
+ mBeganFromDefaultDisplayOn = defaultDisplayOn;
}
interceptKeyDown(event);
} else {
@@ -388,6 +390,10 @@ public final class SingleKeyGestureDetector {
return mBeganFromNonInteractive;
}
+ boolean beganFromDefaultDisplayOn() {
+ return mBeganFromDefaultDisplayOn;
+ }
+
void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "SingleKey rules:");
for (SingleKeyRule rule : mRules) {
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 33bed3d42e50..577468b0c749 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -56,6 +56,7 @@ import java.util.Objects;
public final class HintManagerService extends SystemService {
private static final String TAG = "HintManagerService";
private static final boolean DEBUG = false;
+ private static final int MAX_HINT_SESSION_COUNT_PER_UID = 20;
@VisibleForTesting final long mHintSessionPreferredRate;
// Multi-level map storing all active AppHintSessions.
@@ -367,6 +368,23 @@ public final class HintManagerService extends SystemService {
+ " not be empty.");
final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ int sessionCount = 0;
+ synchronized (mLock) {
+ ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
+ mActiveSessions.get(callingUid);
+ if (tokenMap != null) {
+ for (ArraySet<AppHintSession> arr : tokenMap.values()) {
+ sessionCount += arr.size();
+ }
+ }
+ }
+ if (sessionCount >= MAX_HINT_SESSION_COUNT_PER_UID) {
+ throw new IllegalStateException(
+ "Max session count limit reached: " + sessionCount);
+ }
+ }
+
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java
new file mode 100644
index 000000000000..6cc9d0a54607
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.DurationMillisLong;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.IndentingPrintWriter;
+
+import com.android.internal.os.PowerStats;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class represents aggregated power stats for a variety of power components (CPU, WiFi,
+ * etc) covering a specific period of power usage history.
+ */
+class AggregatedPowerStats {
+ private final PowerComponentAggregatedPowerStats[] mPowerComponentStats;
+
+ @CurrentTimeMillisLong
+ private long mStartTime;
+
+ @DurationMillisLong
+ private long mDurationMs;
+
+ AggregatedPowerStats(PowerComponentAggregatedPowerStats... powerComponentAggregatedPowerStats) {
+ this.mPowerComponentStats = powerComponentAggregatedPowerStats;
+ }
+
+ void setStartTime(@CurrentTimeMillisLong long startTime) {
+ mStartTime = startTime;
+ }
+
+ @CurrentTimeMillisLong
+ public long getStartTime() {
+ return mStartTime;
+ }
+
+ void setDuration(long durationMs) {
+ mDurationMs = durationMs;
+ }
+
+ @DurationMillisLong
+ public long getDuration() {
+ return mDurationMs;
+ }
+
+ PowerComponentAggregatedPowerStats getPowerComponentStats(int powerComponentId) {
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ if (stats.powerComponentId == powerComponentId) {
+ return stats;
+ }
+ }
+ return null;
+ }
+
+ void setDeviceState(@PowerStatsAggregator.TrackedState int stateId, int state, long time) {
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ stats.setState(stateId, state, time);
+ }
+ }
+
+ void setUidState(int uid, @PowerStatsAggregator.TrackedState int stateId, int state,
+ long time) {
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ stats.setUidState(uid, stateId, state, time);
+ }
+ }
+
+ boolean isCompatible(PowerStats powerStats) {
+ int powerComponentId = powerStats.descriptor.powerComponentId;
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ if (stats.powerComponentId == powerComponentId && !stats.isCompatible(powerStats)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void addPowerStats(PowerStats powerStats, long time) {
+ int powerComponentId = powerStats.descriptor.powerComponentId;
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ if (stats.powerComponentId == powerComponentId) {
+ stats.addPowerStats(powerStats, time);
+ }
+ }
+ }
+
+ void reset() {
+ mStartTime = 0;
+ mDurationMs = 0;
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ stats.reset();
+ }
+ }
+
+ void dump(PrintWriter pw) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+ ipw.print("Start time: ");
+ ipw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartTime));
+ ipw.print(" duration: ");
+ ipw.print(mDurationMs);
+ ipw.println();
+
+ ipw.println("Device");
+ ipw.increaseIndent();
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ stats.dumpDevice(ipw);
+ }
+ ipw.decreaseIndent();
+
+ Set<Integer> uids = new HashSet<>();
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ stats.collectUids(uids);
+ }
+
+ Integer[] allUids = uids.toArray(new Integer[uids.size()]);
+ Arrays.sort(allUids);
+ for (int uid : allUids) {
+ ipw.println(UserHandle.formatUid(uid));
+ ipw.increaseIndent();
+ for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
+ stats.dumpUid(ipw, uid);
+ }
+ ipw.decreaseIndent();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index f4b2f52eef9c..f9d57e4c9042 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -342,20 +342,24 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat
@Override
public Future<?> scheduleCleanupDueToRemovedUser(int userId) {
synchronized (BatteryExternalStatsWorker.this) {
- // Initial quick clean-up after a user removal
- mExecutorService.schedule(() -> {
- synchronized (mStats) {
- mStats.clearRemovedUserUidsLocked(userId);
- }
- }, UID_QUICK_REMOVAL_AFTER_USER_REMOVAL_DELAY_MILLIS, TimeUnit.MILLISECONDS);
+ try {
+ // Initial quick clean-up after a user removal
+ mExecutorService.schedule(() -> {
+ synchronized (mStats) {
+ mStats.clearRemovedUserUidsLocked(userId);
+ }
+ }, UID_QUICK_REMOVAL_AFTER_USER_REMOVAL_DELAY_MILLIS, TimeUnit.MILLISECONDS);
- // Final clean-up after a user removal, to take care of UIDs that were running longer
- // than expected
- return mExecutorService.schedule(() -> {
- synchronized (mStats) {
- mStats.clearRemovedUserUidsLocked(userId);
- }
- }, UID_FINAL_REMOVAL_AFTER_USER_REMOVAL_DELAY_MILLIS, TimeUnit.MILLISECONDS);
+ // Final clean-up after a user removal, to take care of UIDs that were running
+ // longer than expected
+ return mExecutorService.schedule(() -> {
+ synchronized (mStats) {
+ mStats.clearRemovedUserUidsLocked(userId);
+ }
+ }, UID_FINAL_REMOVAL_AFTER_USER_REMOVAL_DELAY_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (RejectedExecutionException e) {
+ return CompletableFuture.failedFuture(e);
+ }
}
}
@@ -401,7 +405,11 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat
scheduleSyncLocked("write", UPDATE_ALL);
// Since we use a single threaded executor, we can assume the next scheduled task's
// Future finishes after the sync.
- return mExecutorService.submit(mWriteTask);
+ try {
+ return mExecutorService.submit(mWriteTask);
+ } catch (RejectedExecutionException e) {
+ return CompletableFuture.failedFuture(e);
+ }
}
/**
@@ -429,7 +437,11 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat
if (mCurrentFuture == null) {
mUpdateFlags = flags;
mCurrentReason = reason;
- mCurrentFuture = mExecutorService.submit(mSyncTask);
+ try {
+ mCurrentFuture = mExecutorService.submit(mSyncTask);
+ } catch (RejectedExecutionException e) {
+ return CompletableFuture.failedFuture(e);
+ }
}
mUpdateFlags |= flags;
return mCurrentFuture;
@@ -687,12 +699,6 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat
BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS,
reason, 0);
- if (energyConsumerDeltas != null && !energyConsumerDeltas.isEmpty()
- && mStats.isUsageHistoryEnabled()) {
- mStats.recordEnergyConsumerDetailsLocked(elapsedRealtime, uptime,
- mEnergyConsumerSnapshot.getEnergyConsumerDetails(energyConsumerDeltas));
- }
-
if ((updateFlags & UPDATE_CPU) != 0) {
if (useLatestStates) {
onBattery = mStats.isOnBatteryLocked();
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index cf4e845a273b..613f18982b86 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -125,6 +125,7 @@ import com.android.internal.os.KernelSingleUidTimeReader;
import com.android.internal.os.LongArrayMultiStateCounter;
import com.android.internal.os.LongMultiStateCounter;
import com.android.internal.os.PowerProfile;
+import com.android.internal.os.PowerStats;
import com.android.internal.os.RailStats;
import com.android.internal.os.RpmStats;
import com.android.internal.power.EnergyConsumerStats;
@@ -135,6 +136,7 @@ import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.NetworkCapabilitiesUtils;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
import libcore.util.EmptyArray;
@@ -280,7 +282,8 @@ public class BatteryStatsImpl extends BatteryStats {
= new KernelMemoryBandwidthStats();
private final LongSparseArray<SamplingTimer> mKernelMemoryStats = new LongSparseArray<>();
private int[] mCpuPowerBracketMap;
- private final CpuUsageDetails mCpuUsageDetails = new CpuUsageDetails();
+ private final CpuPowerStatsCollector mCpuPowerStatsCollector;
+ private final PowerStatsAggregator mPowerStatsAggregator;
public LongSparseArray<SamplingTimer> getKernelMemoryStats() {
return mKernelMemoryStats;
@@ -439,6 +442,7 @@ public class BatteryStatsImpl extends BatteryStats {
static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1;
private final int mFlags;
+ private final long mPowerStatsThrottlePeriodCpu;
private BatteryStatsConfig(Builder builder) {
int flags = 0;
@@ -449,6 +453,7 @@ public class BatteryStatsImpl extends BatteryStats {
flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
}
mFlags = flags;
+ mPowerStatsThrottlePeriodCpu = builder.mPowerStatsThrottlePeriodCpu;
}
/**
@@ -469,15 +474,22 @@ public class BatteryStatsImpl extends BatteryStats {
== RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
}
+ long getPowerStatsThrottlePeriodCpu() {
+ return mPowerStatsThrottlePeriodCpu;
+ }
+
/**
* Builder for BatteryStatsConfig
*/
public static class Builder {
private boolean mResetOnUnplugHighBatteryLevel;
private boolean mResetOnUnplugAfterSignificantCharge;
+ private long mPowerStatsThrottlePeriodCpu;
+
public Builder() {
mResetOnUnplugHighBatteryLevel = true;
mResetOnUnplugAfterSignificantCharge = true;
+ mPowerStatsThrottlePeriodCpu = 60000;
}
/**
@@ -504,8 +516,16 @@ public class BatteryStatsImpl extends BatteryStats {
mResetOnUnplugAfterSignificantCharge = reset;
return this;
}
- }
+ /**
+ * Sets the minimum amount of time (in millis) to wait between passes
+ * of CPU power stats collection.
+ */
+ public Builder setPowerStatsThrottlePeriodCpu(long periodMs) {
+ mPowerStatsThrottlePeriodCpu = periodMs;
+ return this;
+ }
+ }
}
private final PlatformIdleStateCallback mPlatformIdleStateCallback;
@@ -595,15 +615,8 @@ public class BatteryStatsImpl extends BatteryStats {
LongArrayMultiStateCounter onBatteryScreenOffCounter =
u.getProcStateScreenOffTimeCounter(elapsedRealtimeMs).getCounter();
- if (isUsageHistoryEnabled()) {
- LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
- getCpuTimeInFreqContainer();
- mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, elapsedRealtimeMs,
- deltaContainer);
- recordCpuUsage(uid, deltaContainer, elapsedRealtimeMs, uptimeMs);
- } else {
- mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, elapsedRealtimeMs);
- }
+
+ mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, elapsedRealtimeMs);
mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, elapsedRealtimeMs);
if (u.mChildUids != null) {
@@ -617,25 +630,12 @@ public class BatteryStatsImpl extends BatteryStats {
mKernelSingleUidTimeReader.addDelta(u.mChildUids.keyAt(j),
cpuTimeInFreqCounter, elapsedRealtimeMs, deltaContainer);
onBatteryCounter.addCounts(deltaContainer);
- if (isUsageHistoryEnabled()) {
- recordCpuUsage(uid, deltaContainer, elapsedRealtimeMs, uptimeMs);
- }
onBatteryScreenOffCounter.addCounts(deltaContainer);
}
}
}
}
- private void recordCpuUsage(int uid, LongArrayMultiStateCounter.LongArrayContainer cpuUsage,
- long elapsedRealtimeMs, long uptimeMs) {
- if (!cpuUsage.combineValues(mCpuUsageDetails.cpuUsageMs, mCpuPowerBracketMap)) {
- return;
- }
-
- mCpuUsageDetails.uid = uid;
- mHistory.recordCpuUsage(elapsedRealtimeMs, uptimeMs, mCpuUsageDetails);
- }
-
/**
* Removes kernel CPU stats for removed UIDs, in the order they were added to the
* mPendingRemovedUids queue.
@@ -656,6 +656,10 @@ public class BatteryStatsImpl extends BatteryStats {
*/
@SuppressWarnings("GuardedBy") // errorprone false positive on getProcStateTimeCounter
public void updateCpuTimesForAllUids() {
+ if (mCpuPowerStatsCollector != null) {
+ mCpuPowerStatsCollector.schedule();
+ }
+
synchronized (BatteryStatsImpl.this) {
if (!trackPerProcStateCpuTimes()) {
return;
@@ -687,16 +691,8 @@ public class BatteryStatsImpl extends BatteryStats {
u.getProcStateScreenOffTimeCounter(elapsedRealtimeMs).getCounter();
if (uid == parentUid || Process.isSdkSandboxUid(uid)) {
- if (isUsageHistoryEnabled()) {
- LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
- getCpuTimeInFreqContainer();
- mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryCounter,
- elapsedRealtimeMs, deltaContainer);
- recordCpuUsage(parentUid, deltaContainer, elapsedRealtimeMs, uptimeMs);
- } else {
- mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryCounter,
- elapsedRealtimeMs);
- }
+ mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryCounter,
+ elapsedRealtimeMs);
mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryScreenOffCounter,
elapsedRealtimeMs);
} else {
@@ -709,9 +705,6 @@ public class BatteryStatsImpl extends BatteryStats {
mKernelSingleUidTimeReader.addDelta(uid, counter, elapsedRealtimeMs,
deltaContainer);
onBatteryCounter.addCounts(deltaContainer);
- if (isUsageHistoryEnabled()) {
- recordCpuUsage(uid, deltaContainer, elapsedRealtimeMs, uptimeMs);
- }
onBatteryScreenOffCounter.addCounts(deltaContainer);
}
}
@@ -842,6 +835,8 @@ public class BatteryStatsImpl extends BatteryStats {
private final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
private final HistoryStepDetailsCalculatorImpl mStepDetailsCalculator =
new HistoryStepDetailsCalculatorImpl();
+ private final PowerStats.DescriptorRegistry mPowerStatsDescriptorRegistry =
+ new PowerStats.DescriptorRegistry();
private boolean mHaveBatteryLevel = false;
private boolean mBatteryPluggedIn;
@@ -1556,7 +1551,7 @@ public class BatteryStatsImpl extends BatteryStats {
@VisibleForTesting
@GuardedBy("this")
- protected BatteryStatsConfig mBatteryStatsConfig = new BatteryStatsConfig.Builder().build();
+ protected BatteryStatsConfig mBatteryStatsConfig;
@GuardedBy("this")
private AlarmManager mAlarmManager = null;
@@ -1733,6 +1728,7 @@ public class BatteryStatsImpl extends BatteryStats {
public BatteryStatsImpl(Clock clock, File historyDirectory) {
init(clock);
+ mBatteryStatsConfig = new BatteryStatsConfig.Builder().build();
mHandler = null;
mConstants = new Constants(mHandler);
mStartClockTimeMs = clock.currentTimeMillis();
@@ -1751,6 +1747,8 @@ public class BatteryStatsImpl extends BatteryStats {
mPlatformIdleStateCallback = null;
mEnergyConsumerRetriever = null;
mUserInfoProvider = null;
+ mCpuPowerStatsCollector = null;
+ mPowerStatsAggregator = null;
}
private void init(Clock clock) {
@@ -4383,6 +4381,12 @@ public class BatteryStatsImpl extends BatteryStats {
public void noteCurrentTimeChangedLocked(long currentTimeMs,
long elapsedRealtimeMs, long uptimeMs) {
mHistory.recordCurrentTimeChange(elapsedRealtimeMs, uptimeMs, currentTimeMs);
+ adjustStartClockTime(currentTimeMs);
+ }
+
+ private void adjustStartClockTime(long currentTimeMs) {
+ mStartClockTimeMs =
+ currentTimeMs - (mClock.elapsedRealtime() - (mRealtimeStartUs / 1000));
}
@GuardedBy("this")
@@ -7654,18 +7658,6 @@ public class BatteryStatsImpl extends BatteryStats {
return names;
}
- /**
- * Adds energy consumer delta to battery history.
- */
- @GuardedBy("this")
- public void recordEnergyConsumerDetailsLocked(long elapsedRealtimeMs,
- long uptimeMs, EnergyConsumerDetails energyConsumerDetails) {
- if (isUsageHistoryEnabled()) {
- mHistory.recordEnergyConsumerDetails(elapsedRealtimeMs, uptimeMs,
- energyConsumerDetails);
- }
- }
-
@GuardedBy("this")
@Override public long getStartClockTime() {
final long currentTimeMs = mClock.currentTimeMillis();
@@ -7676,9 +7668,8 @@ public class BatteryStatsImpl extends BatteryStats {
// the previous time was completely bogus. So we are going to figure out a
// new time based on how much time has elapsed since we started counting.
mHistory.recordCurrentTimeChange(mClock.elapsedRealtime(), mClock.uptimeMillis(),
- currentTimeMs
- );
- return currentTimeMs - (mClock.elapsedRealtime() - (mRealtimeStartUs / 1000));
+ currentTimeMs);
+ adjustStartClockTime(currentTimeMs);
}
return mStartClockTimeMs;
}
@@ -10569,6 +10560,10 @@ public class BatteryStatsImpl extends BatteryStats {
final int batteryConsumerProcessState =
mapUidProcessStateToBatteryConsumerProcessState(uidRunningState);
+ if (mBsi.mSystemReady && Flags.streamlinedBatteryStats()) {
+ mBsi.mHistory.recordProcessStateChange(elapsedRealtimeMs, uptimeMs, mUid,
+ batteryConsumerProcessState);
+ }
getCpuActiveTimeCounter().setState(batteryConsumerProcessState, elapsedRealtimeMs);
getMobileRadioActiveTimeCounter()
@@ -10911,21 +10906,23 @@ public class BatteryStatsImpl extends BatteryStats {
return mTmpCpuTimeInFreq;
}
- public BatteryStatsImpl(@Nullable File systemDir, @NonNull Handler handler,
- @Nullable PlatformIdleStateCallback cb, @Nullable EnergyStatsRetriever energyStatsCb,
+ public BatteryStatsImpl(@NonNull BatteryStatsConfig config, @Nullable File systemDir,
+ @NonNull Handler handler, @Nullable PlatformIdleStateCallback cb,
+ @Nullable EnergyStatsRetriever energyStatsCb,
@NonNull UserInfoProvider userInfoProvider, @NonNull PowerProfile powerProfile,
@NonNull CpuScalingPolicies cpuScalingPolicies) {
- this(Clock.SYSTEM_CLOCK, systemDir, handler, cb, energyStatsCb, userInfoProvider,
+ this(config, Clock.SYSTEM_CLOCK, systemDir, handler, cb, energyStatsCb, userInfoProvider,
powerProfile, cpuScalingPolicies);
}
- private BatteryStatsImpl(@NonNull Clock clock, @Nullable File systemDir,
- @NonNull Handler handler, @Nullable PlatformIdleStateCallback cb,
- @Nullable EnergyStatsRetriever energyStatsCb,
+ private BatteryStatsImpl(@NonNull BatteryStatsConfig config, @NonNull Clock clock,
+ @Nullable File systemDir, @NonNull Handler handler,
+ @Nullable PlatformIdleStateCallback cb, @Nullable EnergyStatsRetriever energyStatsCb,
@NonNull UserInfoProvider userInfoProvider, @NonNull PowerProfile powerProfile,
@NonNull CpuScalingPolicies cpuScalingPolicies) {
init(clock);
+ mBatteryStatsConfig = config;
mHandler = new MyHandler(handler.getLooper());
mConstants = new Constants(mHandler);
@@ -10947,6 +10944,23 @@ public class BatteryStatsImpl extends BatteryStats {
mHistory = new BatteryStatsHistory(systemDir, mConstants.MAX_HISTORY_FILES,
mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock);
}
+
+ mCpuPowerStatsCollector = new CpuPowerStatsCollector(mCpuScalingPolicies, mPowerProfile,
+ mHandler, mBatteryStatsConfig.getPowerStatsThrottlePeriodCpu());
+ mCpuPowerStatsCollector.addConsumer(this::recordPowerStats);
+
+ PowerStatsAggregator.Builder builder = new PowerStatsAggregator.Builder(mHistory);
+ builder.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_CPU)
+ .trackDeviceStates(
+ PowerStatsAggregator.STATE_POWER,
+ PowerStatsAggregator.STATE_SCREEN)
+ .trackUidStates(
+ PowerStatsAggregator.STATE_POWER,
+ PowerStatsAggregator.STATE_SCREEN,
+ PowerStatsAggregator.STATE_PROCESS_STATE);
+
+ mPowerStatsAggregator = builder.build();
+
mStartCount++;
initTimersAndCounters();
mOnBattery = mOnBatteryInternal = false;
@@ -10965,6 +10979,14 @@ public class BatteryStatsImpl extends BatteryStats {
FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
}
+ private void recordPowerStats(PowerStats stats) {
+ if (stats.durationMs > 0) {
+ synchronized (this) {
+ mHistory.recordPowerStats(mClock.elapsedRealtime(), mClock.uptimeMillis(), stats);
+ }
+ }
+ }
+
@VisibleForTesting
protected void initTimersAndCounters() {
mScreenOnTimer = new StopwatchTimer(mClock, null, -1, null, mOnBatteryTimeBase);
@@ -11074,14 +11096,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- int cpuPowerBracketCount = mPowerProfile.getCpuPowerBracketCount();
- mCpuUsageDetails.cpuBracketDescriptions = new String[cpuPowerBracketCount];
- mCpuUsageDetails.cpuUsageMs = new long[cpuPowerBracketCount];
- for (int i = 0; i < cpuPowerBracketCount; i++) {
- mCpuUsageDetails.cpuBracketDescriptions[i] =
- mPowerProfile.getCpuPowerBracketDescription(mCpuScalingPolicies, i);
- }
-
if (mEstimatedBatteryCapacityMah == -1) {
// Initialize the estimated battery capacity to a known preset one.
mEstimatedBatteryCapacityMah = (int) mPowerProfile.getBatteryCapacity();
@@ -11095,15 +11109,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
- * Injects BatteryStatsConfig
- */
- public void setBatteryStatsConfig(BatteryStatsConfig config) {
- synchronized (this) {
- mBatteryStatsConfig = config;
- }
- }
-
- /**
* Starts tracking CPU time-in-state for threads of the system server process,
* keeping a separate account of threads receiving incoming binder calls.
*/
@@ -11466,8 +11471,9 @@ public class BatteryStatsImpl extends BatteryStats {
* Creates an iterator for battery stats history.
*/
@Override
- public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
- return mHistory.copy().iterate();
+ public BatteryStatsHistoryIterator iterateBatteryStatsHistory(long startTimeMs,
+ long endTimeMs) {
+ return mHistory.copy().iterate(startTimeMs, endTimeMs);
}
@Override
@@ -14197,6 +14203,9 @@ public class BatteryStatsImpl extends BatteryStats {
if (mCpuUidFreqTimeReader != null) {
mCpuUidFreqTimeReader.onSystemReady();
}
+ if (mCpuPowerStatsCollector != null) {
+ mCpuPowerStatsCollector.onSystemReady();
+ }
mSystemReady = true;
}
@@ -15213,11 +15222,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
@GuardedBy("this")
- boolean isUsageHistoryEnabled() {
- return mConstants.RECORD_USAGE_HISTORY;
- }
-
- @GuardedBy("this")
public void systemServicesReady(Context context) {
mConstants.startObserving(context.getContentResolver());
registerUsbStateReceiver(context);
@@ -15328,8 +15332,6 @@ public class BatteryStatsImpl extends BatteryStats {
public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
public static final String KEY_BATTERY_CHARGED_DELAY_MS =
"battery_charged_delay_ms";
- public static final String KEY_RECORD_USAGE_HISTORY =
- "record_usage_history";
public static final String KEY_PER_UID_MODEM_POWER_MODEL =
"per_uid_modem_power_model";
public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION =
@@ -15380,7 +15382,6 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
- private static final boolean DEFAULT_RECORD_USAGE_HISTORY = false;
@PerUidModemPowerModel
private static final int DEFAULT_PER_UID_MODEM_MODEL =
PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
@@ -15402,7 +15403,6 @@ public class BatteryStatsImpl extends BatteryStats {
public int MAX_HISTORY_FILES;
public int MAX_HISTORY_BUFFER; /*Bytes*/
public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
- public boolean RECORD_USAGE_HISTORY = DEFAULT_RECORD_USAGE_HISTORY;
public int PER_UID_MODEM_MODEL = DEFAULT_PER_UID_MODEM_MODEL;
public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION =
DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION;
@@ -15483,8 +15483,6 @@ public class BatteryStatsImpl extends BatteryStats {
DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
: DEFAULT_MAX_HISTORY_BUFFER_KB)
* 1024;
- RECORD_USAGE_HISTORY = mParser.getBoolean(
- KEY_RECORD_USAGE_HISTORY, DEFAULT_RECORD_USAGE_HISTORY);
final String perUidModemModel = mParser.getString(KEY_PER_UID_MODEM_POWER_MODEL,
"");
PER_UID_MODEM_MODEL = getPerUidModemModel(perUidModemModel);
@@ -15562,8 +15560,6 @@ public class BatteryStatsImpl extends BatteryStats {
pw.println(MAX_HISTORY_BUFFER/1024);
pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
pw.println(BATTERY_CHARGED_DELAY_MS);
- pw.print(KEY_RECORD_USAGE_HISTORY); pw.print("=");
- pw.println(RECORD_USAGE_HISTORY);
pw.print(KEY_PER_UID_MODEM_POWER_MODEL); pw.print("=");
pw.println(getPerUidModemModelName(PER_UID_MODEM_MODEL));
pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("=");
@@ -15705,6 +15701,21 @@ public class BatteryStatsImpl extends BatteryStats {
iPw.decreaseIndent();
}
+ /**
+ * Grabs one sample of PowerStats and prints it.
+ */
+ public void dumpStatsSample(PrintWriter pw) {
+ mCpuPowerStatsCollector.collectAndDump(pw);
+ }
+
+ /**
+ * Aggregates power stats between the specified times and prints them.
+ */
+ public void dumpAggregatedStats(PrintWriter pw, long startTimeMs, long endTimeMs) {
+ mPowerStatsAggregator.aggregateBatteryStats(startTimeMs, endTimeMs,
+ stats-> stats.dump(pw));
+ }
+
private final Runnable mWriteAsyncRunnable = () -> {
synchronized (BatteryStatsImpl.this) {
writeSyncLocked();
diff --git a/services/core/java/com/android/server/power/stats/CpuAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/CpuAggregatedPowerStats.java
new file mode 100644
index 000000000000..5b3fe064d79a
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/CpuAggregatedPowerStats.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.os.BatteryConsumer;
+
+import com.android.internal.os.MultiStateStats;
+
+class CpuAggregatedPowerStats extends PowerComponentAggregatedPowerStats {
+
+ CpuAggregatedPowerStats(MultiStateStats.States[] deviceStates,
+ MultiStateStats.States[] uidStates) {
+ super(BatteryConsumer.POWER_COMPONENT_CPU, deviceStates, uidStates);
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
new file mode 100644
index 000000000000..376ca897fbd1
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.os.BatteryConsumer;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.Keep;
+import com.android.internal.annotations.VisibleForNative;
+import com.android.internal.os.Clock;
+import com.android.internal.os.CpuScalingPolicies;
+import com.android.internal.os.PowerProfile;
+import com.android.internal.os.PowerStats;
+import com.android.server.power.optimization.Flags;
+
+/**
+ * Collects snapshots of power-related system statistics.
+ * <p>
+ * The class is intended to be used in a serialized fashion using the handler supplied in the
+ * constructor. Thus the object is not thread-safe except where noted.
+ */
+public class CpuPowerStatsCollector extends PowerStatsCollector {
+ private static final long NANOS_PER_MILLIS = 1000000;
+
+ private final KernelCpuStatsReader mKernelCpuStatsReader;
+ private final int[] mScalingStepToPowerBracketMap;
+ private final long[] mTempUidStats;
+ private final SparseArray<UidStats> mUidStats = new SparseArray<>();
+ private final int mUidStatsSize;
+ // Reusable instance
+ private final PowerStats mCpuPowerStats;
+ private long mLastUpdateTimestampNanos;
+
+ public CpuPowerStatsCollector(CpuScalingPolicies cpuScalingPolicies, PowerProfile powerProfile,
+ Handler handler, long throttlePeriodMs) {
+ this(cpuScalingPolicies, powerProfile, handler, new KernelCpuStatsReader(),
+ throttlePeriodMs, Clock.SYSTEM_CLOCK);
+ }
+
+ public CpuPowerStatsCollector(CpuScalingPolicies cpuScalingPolicies, PowerProfile powerProfile,
+ Handler handler, KernelCpuStatsReader kernelCpuStatsReader,
+ long throttlePeriodMs, Clock clock) {
+ super(handler, throttlePeriodMs, clock);
+ mKernelCpuStatsReader = kernelCpuStatsReader;
+
+ int scalingStepCount = cpuScalingPolicies.getScalingStepCount();
+ mScalingStepToPowerBracketMap = new int[scalingStepCount];
+ int index = 0;
+ for (int policy : cpuScalingPolicies.getPolicies()) {
+ int[] frequencies = cpuScalingPolicies.getFrequencies(policy);
+ for (int step = 0; step < frequencies.length; step++) {
+ int bracket = powerProfile.getCpuPowerBracketForScalingStep(policy, step);
+ mScalingStepToPowerBracketMap[index++] = bracket;
+ }
+ }
+ mUidStatsSize = powerProfile.getCpuPowerBracketCount();
+ mTempUidStats = new long[mUidStatsSize];
+
+ mCpuPowerStats = new PowerStats(
+ new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU, 0, mUidStatsSize,
+ new PersistableBundle()));
+ }
+
+ /**
+ * Initializes the collector during the boot sequence.
+ */
+ public void onSystemReady() {
+ setEnabled(Flags.streamlinedBatteryStats());
+ }
+
+ @Override
+ protected PowerStats collectStats() {
+ mCpuPowerStats.uidStats.clear();
+ long newTimestampNanos = mKernelCpuStatsReader.nativeReadCpuStats(
+ this::processUidStats, mScalingStepToPowerBracketMap, mLastUpdateTimestampNanos,
+ mTempUidStats);
+ mCpuPowerStats.durationMs =
+ (newTimestampNanos - mLastUpdateTimestampNanos) / NANOS_PER_MILLIS;
+ mLastUpdateTimestampNanos = newTimestampNanos;
+ return mCpuPowerStats;
+ }
+
+ @VisibleForNative
+ interface KernelCpuStatsCallback {
+ @Keep // Called from native
+ void processUidStats(int uid, long[] stats);
+ }
+
+ private void processUidStats(int uid, long[] stats) {
+ UidStats uidStats = mUidStats.get(uid);
+ if (uidStats == null) {
+ uidStats = new UidStats();
+ uidStats.stats = new long[mUidStatsSize];
+ uidStats.delta = new long[mUidStatsSize];
+ mUidStats.put(uid, uidStats);
+ }
+
+ boolean nonzero = false;
+ for (int i = mUidStatsSize - 1; i >= 0; i--) {
+ long delta = uidStats.delta[i] = stats[i] - uidStats.stats[i];
+ if (delta != 0) {
+ nonzero = true;
+ }
+ uidStats.stats[i] = stats[i];
+ }
+ if (nonzero) {
+ mCpuPowerStats.uidStats.put(uid, uidStats.delta);
+ }
+ }
+
+ /**
+ * Native class that retrieves CPU stats from the kernel.
+ */
+ public static class KernelCpuStatsReader {
+ protected native long nativeReadCpuStats(KernelCpuStatsCallback callback,
+ int[] scalingStepToPowerBracketMap, long lastUpdateTimestampNanos,
+ long[] tempForUidStats);
+ }
+
+ private static class UidStats {
+ public long[] stats;
+ public long[] delta;
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java b/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java
index 939a08ba0b6a..7f50ae02aa39 100644
--- a/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java
+++ b/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java
@@ -23,7 +23,6 @@ import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerAttribution;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
-import android.os.BatteryStats.EnergyConsumerDetails;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -85,8 +84,6 @@ public class EnergyConsumerSnapshot {
*/
private final SparseArray<SparseLongArray> mAttributionSnapshots;
- private EnergyConsumerDetails mEnergyConsumerDetails;
-
/**
* Constructor that initializes to the given id->EnergyConsumer map, indicating which consumers
* exist and what their details are.
@@ -423,122 +420,4 @@ public class EnergyConsumerSnapshot {
// since the last snapshot. Round off to the nearest whole long.
return (deltaEnergyUJ * MILLIVOLTS_PER_VOLT + (avgVoltageMV / 2)) / avgVoltageMV;
}
-
- /**
- * Converts the EnergyConsumerDeltaData object to EnergyConsumerDetails, which can
- * be saved in battery history.
- */
- EnergyConsumerDetails getEnergyConsumerDetails(
- EnergyConsumerDeltaData delta) {
- if (mEnergyConsumerDetails == null) {
- mEnergyConsumerDetails = createEnergyConsumerDetails();
- }
-
- final long[] chargeUC = mEnergyConsumerDetails.chargeUC;
- for (int i = 0; i < mEnergyConsumerDetails.consumers.length; i++) {
- EnergyConsumerDetails.EnergyConsumer energyConsumer =
- mEnergyConsumerDetails.consumers[i];
- switch (energyConsumer.type) {
- case EnergyConsumerType.BLUETOOTH:
- chargeUC[i] = delta.bluetoothChargeUC;
- break;
- case EnergyConsumerType.CPU_CLUSTER:
- if (delta.cpuClusterChargeUC != null) {
- chargeUC[i] = delta.cpuClusterChargeUC[energyConsumer.ordinal];
- } else {
- chargeUC[i] = UNAVAILABLE;
- }
- break;
- case EnergyConsumerType.DISPLAY:
- if (delta.displayChargeUC != null) {
- chargeUC[i] = delta.displayChargeUC[energyConsumer.ordinal];
- } else {
- chargeUC[i] = UNAVAILABLE;
- }
- break;
- case EnergyConsumerType.GNSS:
- chargeUC[i] = delta.gnssChargeUC;
- break;
- case EnergyConsumerType.MOBILE_RADIO:
- chargeUC[i] = delta.mobileRadioChargeUC;
- break;
- case EnergyConsumerType.WIFI:
- chargeUC[i] = delta.wifiChargeUC;
- break;
- case EnergyConsumerType.CAMERA:
- chargeUC[i] = delta.cameraChargeUC;
- break;
- case EnergyConsumerType.OTHER:
- if (delta.otherTotalChargeUC != null) {
- chargeUC[i] = delta.otherTotalChargeUC[energyConsumer.ordinal];
- } else {
- chargeUC[i] = UNAVAILABLE;
- }
- break;
- default:
- chargeUC[i] = UNAVAILABLE;
- break;
- }
- }
- return mEnergyConsumerDetails;
- }
-
- private EnergyConsumerDetails createEnergyConsumerDetails() {
- EnergyConsumerDetails details = new EnergyConsumerDetails();
- details.consumers =
- new EnergyConsumerDetails.EnergyConsumer[mEnergyConsumers.size()];
- for (int i = 0; i < mEnergyConsumers.size(); i++) {
- EnergyConsumer energyConsumer = mEnergyConsumers.valueAt(i);
- EnergyConsumerDetails.EnergyConsumer consumer =
- new EnergyConsumerDetails.EnergyConsumer();
- consumer.type = energyConsumer.type;
- consumer.ordinal = energyConsumer.ordinal;
- switch (consumer.type) {
- case EnergyConsumerType.BLUETOOTH:
- consumer.name = "BLUETOOTH";
- break;
- case EnergyConsumerType.CPU_CLUSTER:
- consumer.name = "CPU";
- break;
- case EnergyConsumerType.DISPLAY:
- consumer.name = "DISPLAY";
- break;
- case EnergyConsumerType.GNSS:
- consumer.name = "GNSS";
- break;
- case EnergyConsumerType.MOBILE_RADIO:
- consumer.name = "MOBILE_RADIO";
- break;
- case EnergyConsumerType.WIFI:
- consumer.name = "WIFI";
- break;
- case EnergyConsumerType.OTHER:
- consumer.name = sanitizeCustomBucketName(energyConsumer.name);
- break;
- default:
- consumer.name = "UNKNOWN";
- break;
- }
- if (consumer.type != EnergyConsumerType.OTHER) {
- boolean hasOrdinal = consumer.ordinal != 0;
- if (!hasOrdinal) {
- // See if any other EnergyConsumer of the same type has an ordinal
- for (int j = 0; j < mEnergyConsumers.size(); j++) {
- EnergyConsumer aConsumer = mEnergyConsumers.valueAt(j);
- if (aConsumer.type == consumer.type && aConsumer.ordinal != 0) {
- hasOrdinal = true;
- break;
- }
- }
- }
- if (hasOrdinal) {
- consumer.name = consumer.name + "/" + energyConsumer.ordinal;
- }
- }
- details.consumers[i] = consumer;
- }
-
- details.chargeUC = new long[details.consumers.length];
- return details;
- }
}
diff --git a/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
new file mode 100644
index 000000000000..686268fea22b
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.util.IndentingPrintWriter;
+import android.util.SparseArray;
+
+import com.android.internal.os.MultiStateStats;
+import com.android.internal.os.PowerStats;
+
+import java.util.Collection;
+
+/**
+ * Aggregated power stats for a specific power component (e.g. CPU, WiFi, etc). This class
+ * treats stats as arrays of nonspecific longs. Subclasses contain specific logic to interpret those
+ * longs and use them for calculations such as power attribution. They may use meta-data supplied
+ * as part of the {@link PowerStats.Descriptor}.
+ */
+class PowerComponentAggregatedPowerStats {
+ public final int powerComponentId;
+ private final MultiStateStats.States[] mDeviceStateConfig;
+ private final MultiStateStats.States[] mUidStateConfig;
+ private final int[] mDeviceStates;
+ private final long[] mDeviceStateTimestamps;
+
+ private MultiStateStats.Factory mStatsFactory;
+ private MultiStateStats.Factory mUidStatsFactory;
+ private PowerStats.Descriptor mPowerStatsDescriptor;
+ private MultiStateStats mDeviceStats;
+ private final SparseArray<UidStats> mUidStats = new SparseArray<>();
+
+ private static class UidStats {
+ public int[] states;
+ public long[] stateTimestampMs;
+ public MultiStateStats stats;
+ }
+
+ PowerComponentAggregatedPowerStats(int powerComponentId,
+ MultiStateStats.States[] deviceStates,
+ MultiStateStats.States[] uidStates) {
+ this.powerComponentId = powerComponentId;
+ mDeviceStateConfig = deviceStates;
+ mUidStateConfig = uidStates;
+ mDeviceStates = new int[mDeviceStateConfig.length];
+ mDeviceStateTimestamps = new long[mDeviceStateConfig.length];
+ }
+
+ void setState(@PowerStatsAggregator.TrackedState int stateId, int state, long time) {
+ mDeviceStates[stateId] = state;
+ mDeviceStateTimestamps[stateId] = time;
+
+ if (mDeviceStateConfig[stateId].isTracked()) {
+ if (mDeviceStats != null || createDeviceStats()) {
+ mDeviceStats.setState(stateId, state, time);
+ }
+ }
+
+ if (mUidStateConfig[stateId].isTracked()) {
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ PowerComponentAggregatedPowerStats.UidStats uidStats = mUidStats.valueAt(i);
+ if (uidStats.stats != null || createUidStats(uidStats)) {
+ uidStats.stats.setState(stateId, state, time);
+ }
+ }
+ }
+ }
+
+ void setUidState(int uid, @PowerStatsAggregator.TrackedState int stateId, int state,
+ long time) {
+ if (!mUidStateConfig[stateId].isTracked()) {
+ return;
+ }
+
+ UidStats uidStats = getUidStats(uid);
+ uidStats.states[stateId] = state;
+ uidStats.stateTimestampMs[stateId] = time;
+
+ if (uidStats.stats != null || createUidStats(uidStats)) {
+ uidStats.stats.setState(stateId, state, time);
+ }
+ }
+
+ boolean isCompatible(PowerStats powerStats) {
+ return mPowerStatsDescriptor == null || mPowerStatsDescriptor.equals(powerStats.descriptor);
+ }
+
+ void addPowerStats(PowerStats powerStats, long timestampMs) {
+ mPowerStatsDescriptor = powerStats.descriptor;
+
+ if (mDeviceStats == null) {
+ if (mStatsFactory == null) {
+ mStatsFactory = new MultiStateStats.Factory(
+ mPowerStatsDescriptor.statsArrayLength, mDeviceStateConfig);
+ mUidStatsFactory = new MultiStateStats.Factory(
+ mPowerStatsDescriptor.uidStatsArrayLength, mUidStateConfig);
+ }
+
+ createDeviceStats();
+ }
+
+ mDeviceStats.increment(powerStats.stats, timestampMs);
+
+ for (int i = powerStats.uidStats.size() - 1; i >= 0; i--) {
+ int uid = powerStats.uidStats.keyAt(i);
+ PowerComponentAggregatedPowerStats.UidStats uidStats = getUidStats(uid);
+ if (uidStats.stats == null) {
+ createUidStats(uidStats);
+ }
+ uidStats.stats.increment(powerStats.uidStats.valueAt(i), timestampMs);
+ }
+ }
+
+ void reset() {
+ mPowerStatsDescriptor = null;
+ mStatsFactory = null;
+ mUidStatsFactory = null;
+ mDeviceStats = null;
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ mUidStats.valueAt(i).stats = null;
+ }
+ }
+
+ private UidStats getUidStats(int uid) {
+ // TODO(b/292247660): map isolated and sandbox UIDs
+ UidStats uidStats = mUidStats.get(uid);
+ if (uidStats == null) {
+ uidStats = new UidStats();
+ uidStats.states = new int[mUidStateConfig.length];
+ uidStats.stateTimestampMs = new long[mUidStateConfig.length];
+ mUidStats.put(uid, uidStats);
+ }
+ return uidStats;
+ }
+
+ void collectUids(Collection<Integer> uids) {
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ if (mUidStats.valueAt(i).stats != null) {
+ uids.add(mUidStats.keyAt(i));
+ }
+ }
+ }
+
+ boolean getDeviceStats(long[] outValues, int[] deviceStates) {
+ if (deviceStates.length != mDeviceStateConfig.length) {
+ throw new IllegalArgumentException(
+ "Invalid number of tracked states: " + deviceStates.length
+ + " expected: " + mDeviceStateConfig.length);
+ }
+ if (mDeviceStats != null) {
+ mDeviceStats.getStats(outValues, deviceStates);
+ return true;
+ }
+ return false;
+ }
+
+ boolean getUidStats(long[] outValues, int uid, int[] uidStates) {
+ if (uidStates.length != mUidStateConfig.length) {
+ throw new IllegalArgumentException(
+ "Invalid number of tracked states: " + uidStates.length
+ + " expected: " + mUidStateConfig.length);
+ }
+ UidStats uidStats = mUidStats.get(uid);
+ if (uidStats != null && uidStats.stats != null) {
+ uidStats.stats.getStats(outValues, uidStates);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean createDeviceStats() {
+ if (mStatsFactory == null) {
+ return false;
+ }
+
+ mDeviceStats = mStatsFactory.create();
+ for (int stateId = 0; stateId < mDeviceStateConfig.length; stateId++) {
+ mDeviceStats.setState(stateId, mDeviceStates[stateId],
+ mDeviceStateTimestamps[stateId]);
+ }
+ return true;
+ }
+
+ private boolean createUidStats(UidStats uidStats) {
+ if (mUidStatsFactory == null) {
+ return false;
+ }
+
+ uidStats.stats = mUidStatsFactory.create();
+ for (int stateId = 0; stateId < mDeviceStateConfig.length; stateId++) {
+ uidStats.stats.setState(stateId, mDeviceStates[stateId],
+ mDeviceStateTimestamps[stateId]);
+ }
+ for (int stateId = mDeviceStateConfig.length; stateId < mUidStateConfig.length; stateId++) {
+ uidStats.stats.setState(stateId, uidStats.states[stateId],
+ uidStats.stateTimestampMs[stateId]);
+ }
+ return true;
+ }
+
+ void dumpDevice(IndentingPrintWriter ipw) {
+ if (mDeviceStats != null) {
+ ipw.println(mPowerStatsDescriptor.name);
+ ipw.increaseIndent();
+ mDeviceStats.dump(ipw);
+ ipw.decreaseIndent();
+ }
+ }
+
+ void dumpUid(IndentingPrintWriter ipw, int uid) {
+ UidStats uidStats = mUidStats.get(uid);
+ if (uidStats != null && uidStats.stats != null) {
+ ipw.println(mPowerStatsDescriptor.name);
+ ipw.increaseIndent();
+ uidStats.stats.dump(ipw);
+ ipw.decreaseIndent();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
new file mode 100644
index 000000000000..6a1c1da93163
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power.stats;
+
+import android.annotation.IntDef;
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+
+import com.android.internal.os.BatteryStatsHistory;
+import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.internal.os.MultiStateStats;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+class PowerStatsAggregator {
+ public static final int STATE_POWER = 0;
+ public static final int STATE_SCREEN = 1;
+ public static final int STATE_PROCESS_STATE = 2;
+
+ @IntDef({
+ STATE_POWER,
+ STATE_SCREEN,
+ STATE_PROCESS_STATE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TrackedState {
+ }
+
+ static final int POWER_STATE_BATTERY = 0;
+ static final int POWER_STATE_OTHER = 1; // Plugged in, or on wireless charger, etc.
+ static final String[] STATE_LABELS_POWER = {"pwr-battery", "pwr-other"};
+
+ static final int SCREEN_STATE_ON = 0;
+ static final int SCREEN_STATE_OTHER = 1; // Off, doze etc
+ static final String[] STATE_LABELS_SCREEN = {"scr-on", "scr-other"};
+
+ static final String[] STATE_LABELS_PROCESS_STATE;
+
+ static {
+ String[] procStateLabels = new String[BatteryConsumer.PROCESS_STATE_COUNT];
+ for (int i = 0; i < BatteryConsumer.PROCESS_STATE_COUNT; i++) {
+ procStateLabels[i] = BatteryConsumer.processStateToString(i);
+ }
+ STATE_LABELS_PROCESS_STATE = procStateLabels;
+ }
+
+ private final BatteryStatsHistory mHistory;
+ private final AggregatedPowerStats mStats;
+
+ private PowerStatsAggregator(BatteryStatsHistory history,
+ AggregatedPowerStats aggregatedPowerStats) {
+ mHistory = history;
+ mStats = aggregatedPowerStats;
+ }
+
+ /**
+ * Iterates of the battery history and aggregates power stats between the specified times.
+ * The start and end are specified in the battery-stats monotonic time, which is the
+ * adjusted elapsed time found in HistoryItem.time.
+ * <p>
+ * The aggregated stats are sent to the consumer. One aggregation pass may produce
+ * multiple sets of aggregated stats if there was an incompatible change that occurred in the
+ * middle of the recorded battery history.
+ * <p>
+ * Note: the AggregatedPowerStats object is reused, so the consumer should fully consume
+ * the stats in the <code>accept</code> method and never cache it.
+ */
+ void aggregateBatteryStats(long startTimeMs, long endTimeMs,
+ Consumer<AggregatedPowerStats> consumer) {
+ mStats.reset();
+
+ int currentBatteryState = POWER_STATE_BATTERY;
+ int currentScreenState = SCREEN_STATE_OTHER;
+ long baseTime = -1;
+ long lastTime = 0;
+ try (BatteryStatsHistoryIterator iterator =
+ mHistory.copy().iterate(startTimeMs, endTimeMs)) {
+ while (iterator.hasNext()) {
+ BatteryStats.HistoryItem item = iterator.next();
+
+ if (baseTime < 0) {
+ mStats.setStartTime(item.currentTime);
+ baseTime = item.time;
+ }
+
+ lastTime = item.time;
+
+ int batteryState =
+ (item.states & BatteryStats.HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0
+ ? POWER_STATE_OTHER : POWER_STATE_BATTERY;
+ if (batteryState != currentBatteryState) {
+ mStats.setDeviceState(STATE_POWER, batteryState, item.time);
+ currentBatteryState = batteryState;
+ }
+
+ int screenState =
+ (item.states & BatteryStats.HistoryItem.STATE_SCREEN_ON_FLAG) != 0
+ ? SCREEN_STATE_ON : SCREEN_STATE_OTHER;
+ if (screenState != currentScreenState) {
+ mStats.setDeviceState(STATE_SCREEN, screenState, item.time);
+ currentScreenState = screenState;
+ }
+
+ if (item.processStateChange != null) {
+ mStats.setUidState(item.processStateChange.uid, STATE_PROCESS_STATE,
+ item.processStateChange.processState, item.time);
+ }
+
+ if (item.powerStats != null) {
+ if (!mStats.isCompatible(item.powerStats)) {
+ mStats.setDuration(lastTime - baseTime);
+ consumer.accept(mStats);
+ mStats.reset();
+ mStats.setStartTime(item.currentTime);
+ baseTime = lastTime = item.time;
+ }
+ mStats.addPowerStats(item.powerStats, item.time);
+ }
+ }
+ }
+ mStats.setDuration(lastTime - baseTime);
+ consumer.accept(mStats);
+ }
+
+ static class Builder {
+ static class PowerComponentAggregateStatsBuilder {
+ private final int mPowerComponentId;
+ private @TrackedState int[] mTrackedDeviceStates;
+ private @TrackedState int[] mTrackedUidStates;
+
+ PowerComponentAggregateStatsBuilder(int powerComponentId) {
+ this.mPowerComponentId = powerComponentId;
+ }
+
+ public PowerComponentAggregateStatsBuilder trackDeviceStates(
+ @TrackedState int... states) {
+ mTrackedDeviceStates = states;
+ return this;
+ }
+
+ public PowerComponentAggregateStatsBuilder trackUidStates(@TrackedState int... states) {
+ mTrackedUidStates = states;
+ return this;
+ }
+
+ private PowerComponentAggregatedPowerStats build() {
+ MultiStateStats.States[] deviceStates = new MultiStateStats.States[]{
+ new MultiStateStats.States(isTracked(mTrackedDeviceStates, STATE_POWER),
+ PowerStatsAggregator.STATE_LABELS_POWER),
+ new MultiStateStats.States(isTracked(mTrackedDeviceStates, STATE_SCREEN),
+ PowerStatsAggregator.STATE_LABELS_SCREEN),
+ };
+
+ MultiStateStats.States[] uidStates = new MultiStateStats.States[]{
+ new MultiStateStats.States(isTracked(mTrackedUidStates, STATE_POWER),
+ PowerStatsAggregator.STATE_LABELS_POWER),
+ new MultiStateStats.States(isTracked(mTrackedUidStates, STATE_SCREEN),
+ PowerStatsAggregator.STATE_LABELS_SCREEN),
+ new MultiStateStats.States(
+ isTracked(mTrackedUidStates, STATE_PROCESS_STATE),
+ PowerStatsAggregator.STATE_LABELS_PROCESS_STATE),
+ };
+
+ switch (mPowerComponentId) {
+ case BatteryConsumer.POWER_COMPONENT_CPU:
+ return new CpuAggregatedPowerStats(deviceStates, uidStates);
+ default:
+ return new PowerComponentAggregatedPowerStats(mPowerComponentId,
+ deviceStates, uidStates);
+ }
+ }
+
+ private boolean isTracked(int[] trackedStates, int state) {
+ if (trackedStates == null) {
+ return false;
+ }
+
+ for (int trackedState : trackedStates) {
+ if (trackedState == state) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private final BatteryStatsHistory mHistory;
+ private final List<PowerComponentAggregateStatsBuilder> mPowerComponents =
+ new ArrayList<>();
+
+ Builder(BatteryStatsHistory history) {
+ mHistory = history;
+ }
+
+ PowerComponentAggregateStatsBuilder trackPowerComponent(int powerComponentId) {
+ PowerComponentAggregateStatsBuilder builder = new PowerComponentAggregateStatsBuilder(
+ powerComponentId);
+ mPowerComponents.add(builder);
+ return builder;
+ }
+
+ PowerStatsAggregator build() {
+ return new PowerStatsAggregator(mHistory, new AggregatedPowerStats(
+ mPowerComponents.stream()
+ .map(PowerComponentAggregateStatsBuilder::build)
+ .toArray(PowerComponentAggregatedPowerStats[]::new)));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
new file mode 100644
index 000000000000..b49c89fcf6ad
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.util.FastImmutableArraySet;
+import android.util.IndentingPrintWriter;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.Clock;
+import com.android.internal.os.PowerStats;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+/**
+ * Collects snapshots of power-related system statistics.
+ * <p>
+ * Instances of this class are intended to be used in a serialized fashion using
+ * the handler supplied in the constructor. Thus these objects are not thread-safe
+ * except where noted.
+ */
+public abstract class PowerStatsCollector {
+ private final Handler mHandler;
+ private final Clock mClock;
+ private final long mThrottlePeriodMs;
+ private final Runnable mCollectAndDeliverStats = this::collectAndDeliverStats;
+ private boolean mEnabled;
+ private long mLastScheduledUpdateMs = -1;
+
+ @GuardedBy("this")
+ @SuppressWarnings("unchecked")
+ private volatile FastImmutableArraySet<Consumer<PowerStats>> mConsumerList =
+ new FastImmutableArraySet<Consumer<PowerStats>>(new Consumer[0]);
+
+ public PowerStatsCollector(Handler handler, long throttlePeriodMs, Clock clock) {
+ mHandler = handler;
+ mThrottlePeriodMs = throttlePeriodMs;
+ mClock = clock;
+ }
+
+ /**
+ * Adds a consumer that will receive a callback every time a snapshot of stats is collected.
+ * The method is thread safe.
+ */
+ @SuppressWarnings("unchecked")
+ public void addConsumer(Consumer<PowerStats> consumer) {
+ synchronized (this) {
+ mConsumerList = new FastImmutableArraySet<Consumer<PowerStats>>(
+ Stream.concat(mConsumerList.stream(), Stream.of(consumer))
+ .toArray(Consumer[]::new));
+ }
+ }
+
+ /**
+ * Removes a consumer.
+ * The method is thread safe.
+ */
+ @SuppressWarnings("unchecked")
+ public void removeConsumer(Consumer<PowerStats> consumer) {
+ synchronized (this) {
+ mConsumerList = new FastImmutableArraySet<Consumer<PowerStats>>(
+ mConsumerList.stream().filter(c -> c != consumer)
+ .toArray(Consumer[]::new));
+ }
+ }
+
+ /**
+ * Should be called at most once, before the first invocation of {@link #schedule} or
+ * {@link #forceSchedule}
+ */
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+
+ /**
+ * Returns true if the collector is enabled.
+ */
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ @SuppressWarnings("GuardedBy") // Field is volatile
+ private void collectAndDeliverStats() {
+ PowerStats stats = collectStats();
+ for (Consumer<PowerStats> consumer : mConsumerList) {
+ consumer.accept(stats);
+ }
+ }
+
+ /**
+ * Schedules a stats snapshot collection, throttled in accordance with the
+ * {@link #mThrottlePeriodMs} parameter.
+ */
+ public boolean schedule() {
+ if (!mEnabled) {
+ return false;
+ }
+
+ long uptimeMillis = mClock.uptimeMillis();
+ if (uptimeMillis - mLastScheduledUpdateMs < mThrottlePeriodMs
+ && mLastScheduledUpdateMs >= 0) {
+ return false;
+ }
+ mLastScheduledUpdateMs = uptimeMillis;
+ mHandler.post(mCollectAndDeliverStats);
+ return true;
+ }
+
+ /**
+ * Schedules an immediate snapshot collection, foregoing throttling.
+ */
+ public boolean forceSchedule() {
+ if (!mEnabled) {
+ return false;
+ }
+
+ mHandler.removeCallbacks(mCollectAndDeliverStats);
+ mHandler.postAtFrontOfQueue(mCollectAndDeliverStats);
+ return true;
+ }
+
+ protected abstract PowerStats collectStats();
+
+ /**
+ * Collects a fresh stats snapshot and prints it to the supplied printer.
+ */
+ public void collectAndDump(PrintWriter pw) {
+ if (Thread.currentThread() == mHandler.getLooper().getThread()) {
+ throw new RuntimeException(
+ "Calling this method from the handler thread would cause a deadlock");
+ }
+
+ IndentingPrintWriter out = new IndentingPrintWriter(pw);
+ out.print(getClass().getSimpleName());
+ if (!isEnabled()) {
+ out.println(": disabled");
+ return;
+ }
+ out.println();
+
+ ArrayList<PowerStats> collected = new ArrayList<>();
+ Consumer<PowerStats> consumer = collected::add;
+ addConsumer(consumer);
+
+ try {
+ if (forceSchedule()) {
+ awaitCompletion();
+ }
+ } finally {
+ removeConsumer(consumer);
+ }
+
+ out.increaseIndent();
+ for (PowerStats stats : collected) {
+ stats.dump(out);
+ }
+ out.decreaseIndent();
+ }
+
+ private void awaitCompletion() {
+ ConditionVariable done = new ConditionVariable();
+ mHandler.post(done::open);
+ done.block();
+ }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 0ca560398657..2007079ea5ca 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -121,7 +121,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
} else if (getAvailableRollback(failedPackage) != null) {
// Rollback is available, we may get a callback into #execute
- impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_60;
+ impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
} else if (anyRollbackAvailable) {
// If any rollbacks are available, we will commit them
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
index 2bd7383ddde0..1c5838c165a4 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
@@ -105,14 +105,27 @@ public class RemoteProvisioningService extends SystemService {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
- new RemoteProvisioningShellCommand().dump(pw);
+ final int callerUid = Binder.getCallingUidOrThrow();
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ new RemoteProvisioningShellCommand(getContext(), callerUid).dump(pw);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
}
@Override
public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out,
ParcelFileDescriptor err, String[] args) {
- return new RemoteProvisioningShellCommand().exec(this, in.getFileDescriptor(),
- out.getFileDescriptor(), err.getFileDescriptor(), args);
+ final int callerUid = Binder.getCallingUidOrThrow();
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ return new RemoteProvisioningShellCommand(getContext(), callerUid).exec(this,
+ in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
+ args);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningShellCommand.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningShellCommand.java
index 187b93931f0b..4a6d74658754 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningShellCommand.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningShellCommand.java
@@ -16,22 +16,30 @@
package com.android.server.security.rkp;
+import android.content.Context;
import android.hardware.security.keymint.DeviceInfo;
import android.hardware.security.keymint.IRemotelyProvisionedComponent;
import android.hardware.security.keymint.MacedPublicKey;
import android.hardware.security.keymint.ProtectedData;
import android.hardware.security.keymint.RpcHardwareInfo;
+import android.os.CancellationSignal;
+import android.os.OutcomeReceiver;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ShellCommand;
+import android.security.rkp.service.RegistrationProxy;
+import android.security.rkp.service.RemotelyProvisionedKey;
import android.util.IndentingPrintWriter;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.time.Duration;
import java.util.Base64;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
import co.nstant.in.cbor.CborDecoder;
import co.nstant.in.cbor.CborEncoder;
@@ -54,16 +62,17 @@ class RemoteProvisioningShellCommand extends ShellCommand {
+ "csr [--challenge CHALLENGE] NAME\n"
+ " Generate and print a base64-encoded CSR from the named\n"
+ " IRemotelyProvisionedComponent. A base64-encoded challenge can be provided,\n"
- + " or else it defaults to an empty challenge.\n";
+ + " or else it defaults to an empty challenge.\n"
+ + "certify NAME\n"
+ + " Output the PEM-encoded certificate chain provisioned for the named\n"
+ + " IRemotelyProvisionedComponent.\n";
- @VisibleForTesting
static final String EEK_ED25519_BASE64 = "goRDoQEnoFgqpAEBAycgBiFYIJm57t1e5FL2hcZMYtw+YatXSH11N"
+ "ymtdoAy0rPLY1jZWEAeIghLpLekyNdOAw7+uK8UTKc7b6XN3Np5xitk/pk5r3bngPpmAIUNB5gqrJFcpyUUS"
+ "QY0dcqKJ3rZ41pJ6wIDhEOhASegWE6lAQECWCDQrsEVyirPc65rzMvRlh1l6LHd10oaN7lDOpfVmd+YCAM4G"
+ "CAEIVggvoXnRsSjQlpA2TY6phXQLFh+PdwzAjLS/F4ehyVfcmBYQJvPkOIuS6vRGLEOjl0gJ0uEWP78MpB+c"
+ "gWDvNeCvvpkeC1UEEvAMb9r6B414vAtzmwvT/L1T6XUg62WovGHWAQ=";
- @VisibleForTesting
static final String EEK_P256_BASE64 = "goRDoQEmoFhNpQECAyYgASFYIPcUituX9MxT79JkEcTjdR9mH6RxDGzP"
+ "+glGgHSHVPKtIlggXn9b9uzk9hnM/xM3/Q+hyJPbGAZ2xF3m12p3hsMtr49YQC+XjkL7vgctlUeFR5NAsB/U"
+ "m0ekxESp8qEHhxDHn8sR9L+f6Dvg5zRMFfx7w34zBfTRNDztAgRgehXgedOK/ySEQ6EBJqBYcaYBAgJYIDVz"
@@ -74,14 +83,20 @@ class RemoteProvisioningShellCommand extends ShellCommand {
private static final int ERROR = -1;
private static final int SUCCESS = 0;
+ private static final Duration BIND_TIMEOUT = Duration.ofSeconds(10);
+ private static final int KEY_ID = 452436;
+
+ private final Context mContext;
+ private final int mCallerUid;
private final Injector mInjector;
- RemoteProvisioningShellCommand() {
- this(new Injector());
+ RemoteProvisioningShellCommand(Context context, int callerUid) {
+ this(context, callerUid, new Injector());
}
- @VisibleForTesting
- RemoteProvisioningShellCommand(Injector injector) {
+ RemoteProvisioningShellCommand(Context context, int callerUid, Injector injector) {
+ mContext = context;
+ mCallerUid = callerUid;
mInjector = injector;
}
@@ -102,6 +117,8 @@ class RemoteProvisioningShellCommand extends ShellCommand {
return list();
case "csr":
return csr();
+ case "certify":
+ return certify();
default:
return handleDefaultCommands(cmd);
}
@@ -232,7 +249,45 @@ class RemoteProvisioningShellCommand extends ShellCommand {
return new CborDecoder(bais).decodeNext();
}
- @VisibleForTesting
+ private int certify() throws Exception {
+ String name = getNextArgRequired();
+
+ Executor executor = mContext.getMainExecutor();
+ CancellationSignal cancellationSignal = new CancellationSignal();
+ OutcomeFuture<RemotelyProvisionedKey> key = new OutcomeFuture<>();
+ mInjector.getRegistrationProxy(mContext, mCallerUid, name, executor)
+ .getKeyAsync(KEY_ID, cancellationSignal, executor, key);
+ byte[] encodedCertChain = key.join().getEncodedCertChain();
+ ByteArrayInputStream is = new ByteArrayInputStream(encodedCertChain);
+ PrintWriter pw = getOutPrintWriter();
+ for (Certificate cert : CertificateFactory.getInstance("X.509").generateCertificates(is)) {
+ String encoded = Base64.getEncoder().encodeToString(cert.getEncoded());
+ pw.println("-----BEGIN CERTIFICATE-----");
+ pw.println(encoded.replaceAll("(.{64})", "$1\n").stripTrailing());
+ pw.println("-----END CERTIFICATE-----");
+ }
+ return SUCCESS;
+ }
+
+ /** Treat an OutcomeReceiver as a future for use in synchronous code. */
+ private static class OutcomeFuture<T> implements OutcomeReceiver<T, Exception> {
+ private CompletableFuture<T> mFuture = new CompletableFuture<>();
+
+ @Override
+ public void onResult(T result) {
+ mFuture.complete(result);
+ }
+
+ @Override
+ public void onError(Exception e) {
+ mFuture.completeExceptionally(e);
+ }
+
+ public T join() {
+ return mFuture.join();
+ }
+ }
+
static class Injector {
String[] getIrpcNames() {
return ServiceManager.getDeclaredInstances(IRemotelyProvisionedComponent.DESCRIPTOR);
@@ -248,5 +303,14 @@ class RemoteProvisioningShellCommand extends ShellCommand {
}
return binder;
}
+
+ RegistrationProxy getRegistrationProxy(
+ Context context, int callerUid, String name, Executor executor) {
+ String irpc = IRemotelyProvisionedComponent.DESCRIPTOR + "/" + name;
+ OutcomeFuture<RegistrationProxy> registration = new OutcomeFuture<>();
+ RegistrationProxy.createAsync(
+ context, callerUid, irpc, BIND_TIMEOUT, executor, registration);
+ return registration.join();
+ }
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index cb09aef90420..ffe001055979 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -155,12 +155,12 @@ public final class TvInputManagerService extends SystemService {
// ID of the current user.
@GuardedBy("mLock")
private int mCurrentUserId = UserHandle.USER_SYSTEM;
+ // ID of the current on-screen input.
@GuardedBy("mLock")
- // ID of the current input displayed on the screen.
- private String mCurrentInputId = null;
+ private String mOnScreenInputId = null;
+ // SessionState of the currently active on-screen TIS session.
@GuardedBy("mLock")
- // SessionState of the currently active TIS session.
- private SessionState mCurrentSessionState = null;
+ private SessionState mOnScreenSessionState = null;
// IDs of the running profiles. Their parent user ID should be mCurrentUserId.
@GuardedBy("mLock")
private final Set<Integer> mRunningProfiles = new HashSet<>();
@@ -879,12 +879,12 @@ public final class TvInputManagerService extends SystemService {
sessionState.session = null;
}
}
- if (mCurrentSessionState == sessionState) {
+ if (mOnScreenSessionState == sessionState) {
// only log when releasing the current on-screen session
logExternalInputEvent(FrameworkStatsLog.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__RELEASED,
- mCurrentInputId, sessionState);
- mCurrentInputId = null;
- mCurrentSessionState = null;
+ mOnScreenInputId, sessionState);
+ mOnScreenInputId = null;
+ mOnScreenSessionState = null;
}
removeSessionStateLocked(sessionToken, userId);
return sessionState;
@@ -1079,7 +1079,7 @@ public final class TvInputManagerService extends SystemService {
if (currentCecTvInputInfoUpdated) {
logExternalInputEvent(
FrameworkStatsLog.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__DEVICE_INFO_UPDATED,
- mCurrentInputId, mCurrentSessionState);
+ mOnScreenInputId, mOnScreenSessionState);
}
int n = userState.mCallbacks.beginBroadcast();
@@ -1096,14 +1096,14 @@ public final class TvInputManagerService extends SystemService {
@GuardedBy("mLock")
private boolean isCurrentCecTvInputInfoUpdate(UserState userState, TvInputInfo newInputInfo) {
if (newInputInfo == null || newInputInfo.getId() == null
- || !newInputInfo.getId().equals(mCurrentInputId)) {
+ || !newInputInfo.getId().equals(mOnScreenInputId)) {
return false;
}
if (newInputInfo.getHdmiDeviceInfo() == null
|| !newInputInfo.getHdmiDeviceInfo().isCecDevice()) {
return false;
}
- TvInputState inputState = userState.inputMap.get(mCurrentInputId);
+ TvInputState inputState = userState.inputMap.get(mOnScreenInputId);
if (inputState == null || inputState.info == null) {
return false;
}
@@ -1133,21 +1133,21 @@ public final class TvInputManagerService extends SystemService {
return;
}
if (oldState != state) {
- if (inputId.equals(mCurrentInputId)) {
+ if (inputId.equals(mOnScreenInputId)) {
logExternalInputEvent(
FrameworkStatsLog
.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__CONNECTION_STATE_CHANGED,
- mCurrentInputId, mCurrentSessionState);
- } else if (mCurrentInputId != null) {
- TvInputInfo currentInputInfo = userState.inputMap.get(mCurrentInputId).info;
+ mOnScreenInputId, mOnScreenSessionState);
+ } else if (mOnScreenInputId != null) {
+ TvInputInfo currentInputInfo = userState.inputMap.get(mOnScreenInputId).info;
if (currentInputInfo != null && currentInputInfo.getHdmiDeviceInfo() != null
&& inputId.equals(currentInputInfo.getParentId())) {
logExternalInputEvent(
FrameworkStatsLog
.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__CONNECTION_STATE_CHANGED,
- inputId, mCurrentSessionState);
+ inputId, mOnScreenSessionState);
if (state == INPUT_STATE_CONNECTED_STANDBY) {
- mCurrentInputId = currentInputInfo.getParentId();
+ mOnScreenInputId = currentInputInfo.getParentId();
}
}
}
@@ -1814,19 +1814,22 @@ public final class TvInputManagerService extends SystemService {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
userState);
- if (mCurrentInputId == null
- || !mCurrentInputId.equals(sessionState.inputId)) {
- mCurrentInputId = sessionState.inputId;
- logExternalInputEvent(
- FrameworkStatsLog.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
- sessionState.inputId, sessionState);
- }
if (!sessionState.isCurrent
|| !Objects.equals(sessionState.currentChannel, channelUri)) {
sessionState.isCurrent = true;
sessionState.currentChannel = channelUri;
- mCurrentSessionState = sessionState;
notifyCurrentChannelInfosUpdatedLocked(userState);
+ if (!sessionState.isRecordingSession) {
+ if (mOnScreenInputId == null
+ || !TextUtils.equals(mOnScreenInputId, sessionState.inputId)) {
+ logExternalInputEvent(
+ FrameworkStatsLog
+ .EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
+ sessionState.inputId, sessionState);
+ }
+ mOnScreenInputId = sessionState.inputId;
+ mOnScreenSessionState = sessionState;
+ }
}
if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
// Do not log the watch history for passthrough inputs.
@@ -3055,10 +3058,10 @@ public final class TvInputManagerService extends SystemService {
TvInputInfo tvInputInfo = tvInputState.info;
int inputState = tvInputState.state;
int inputType = tvInputInfo.getType();
- // For non-CEC input, the value of vendorId is 0.
- int vendorId = 0;
- // For non-HDMI input, the value of hdmiPort is 0.
- int hdmiPort = 0;
+ // For non-CEC input, the value of vendorId is 0xFFFFFF (16777215 in decimal).
+ int vendorId = 16777215;
+ // For non-HDMI input, the value of hdmiPort is -1.
+ int hdmiPort = -1;
String tifSessionId = sessionState.sessionId;
if (tvInputInfo.getType() == TvInputInfo.TYPE_HDMI) {
@@ -3436,21 +3439,21 @@ public final class TvInputManagerService extends SystemService {
synchronized (mLock) {
mTvInputHardwareManager.addHdmiInput(id, inputInfo);
addHardwareInputLocked(inputInfo);
- if (mCurrentInputId != null && mCurrentSessionState != null) {
- if (TextUtils.equals(mCurrentInputId, inputInfo.getParentId())) {
+ if (mOnScreenInputId != null && mOnScreenSessionState != null) {
+ if (TextUtils.equals(mOnScreenInputId, inputInfo.getParentId())) {
// catch the use case when a CEC device is plugged in an HDMI port,
// and TV app does not explicitly call tune() to the added CEC input.
logExternalInputEvent(
FrameworkStatsLog.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
- inputInfo.getId(), mCurrentSessionState);
- mCurrentInputId = inputInfo.getId();
- } else if (TextUtils.equals(mCurrentInputId, inputInfo.getId())) {
+ inputInfo.getId(), mOnScreenSessionState);
+ mOnScreenInputId = inputInfo.getId();
+ } else if (TextUtils.equals(mOnScreenInputId, inputInfo.getId())) {
// catch the use case when a CEC device disconnects itself
// and reconnects to update info.
logExternalInputEvent(
FrameworkStatsLog
.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__DEVICE_INFO_UPDATED,
- mCurrentInputId, mCurrentSessionState);
+ mOnScreenInputId, mOnScreenSessionState);
}
}
}
@@ -3555,9 +3558,17 @@ public final class TvInputManagerService extends SystemService {
UserState userState = getOrCreateUserStateLocked(mSessionState.userId);
mSessionState.isCurrent = true;
mSessionState.currentChannel = channelUri;
- mCurrentSessionState = mSessionState;
- mCurrentInputId = mSessionState.inputId;
notifyCurrentChannelInfosUpdatedLocked(userState);
+ if (!mSessionState.isRecordingSession) {
+ if (mOnScreenInputId == null
+ || !TextUtils.equals(mOnScreenInputId, mSessionState.inputId)) {
+ logExternalInputEvent(
+ FrameworkStatsLog.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
+ mSessionState.inputId, mSessionState);
+ }
+ mOnScreenInputId = mSessionState.inputId;
+ mOnScreenSessionState = mSessionState;
+ }
}
} catch (RemoteException e) {
Slog.e(TAG, "error in onChannelRetuned", e);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ddc05194c300..aaf48fbc01f1 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2000,12 +2000,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo) {
if (serviceInfo == null) {
- if (wallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)) {
- clearWallpaperLocked(FLAG_SYSTEM, wallpaper.userId, null);
- clearWallpaperLocked(FLAG_LOCK, wallpaper.userId, reply);
- } else {
- clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, reply);
- }
+ clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, reply);
return;
}
Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
@@ -2037,7 +2032,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
WallpaperData data = null;
synchronized (mLock) {
if (mIsLockscreenLiveWallpaperEnabled) {
- clearWallpaperLocked(callingPackage, which, userId);
+ clearWallpaperLocked(callingPackage, which, userId, null);
} else {
clearWallpaperLocked(which, userId, null);
}
@@ -2057,7 +2052,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
- private void clearWallpaperLocked(String callingPackage, int which, int userId) {
+ private void clearWallpaperLocked(String callingPackage, int which, int userId,
+ IRemoteCallback reply) {
// Might need to bring it in the first time to establish our rewrite
if (!mWallpaperMap.contains(userId)) {
@@ -2111,8 +2107,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper));
}
- // TODO(b/266818039) remove this version of the method
private void clearWallpaperLocked(int which, int userId, IRemoteCallback reply) {
+
+ if (mIsLockscreenLiveWallpaperEnabled) {
+ String callingPackage = mPackageManagerInternal.getNameForUid(getCallingUid());
+ clearWallpaperLocked(callingPackage, which, userId, reply);
+ return;
+ }
+
if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
}
@@ -3284,15 +3286,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
boolean setWallpaperComponent(ComponentName name, String callingPackage,
@SetWallpaperFlags int which, int userId) {
if (mIsLockscreenLiveWallpaperEnabled) {
- return setWallpaperComponentInternal(name, callingPackage, which, userId);
+ return setWallpaperComponentInternal(name, callingPackage, which, userId, null);
} else {
setWallpaperComponentInternalLegacy(name, callingPackage, which, userId);
return true;
}
}
+ private boolean setWallpaperComponent(ComponentName name, @SetWallpaperFlags int which,
+ int userId) {
+ String callingPackage = mPackageManagerInternal.getNameForUid(getCallingUid());
+ return setWallpaperComponentInternal(name, callingPackage, which, userId, null);
+ }
+
private boolean setWallpaperComponentInternal(ComponentName name, String callingPackage,
- @SetWallpaperFlags int which, int userIdIn) {
+ @SetWallpaperFlags int which, int userIdIn, IRemoteCallback reply) {
if (DEBUG) {
Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name);
}
@@ -3341,6 +3349,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
Slog.d(TAG, "publish system wallpaper changed!");
}
liveSync.complete();
+ if (reply != null) reply.sendResult(null);
}
};
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index 70f20075b48c..cdd1a2699e5b 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -161,9 +161,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
final boolean visible = (window.inputConfig & InputConfig.NOT_VISIBLE) == 0;
final boolean isNotClone = (window.inputConfig & InputConfig.CLONE) == 0;
final boolean hasTouchableRegion = !window.touchableRegion.isEmpty();
- final boolean hasNonEmptyFrame =
- (window.frameBottom != window.frameTop) && (window.frameLeft
- != window.frameRight);
+ final boolean hasNonEmptyFrame = !window.frame.isEmpty();
if (visible && isNotClone && hasTouchableRegion && hasNonEmptyFrame) {
tempVisibleWindows.add(window);
}
@@ -694,9 +692,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
instance.mIgnoreDuetoRecentsAnimation = windowState != null && controller != null
&& controller.shouldIgnoreForAccessibility(windowState);
- final Rect windowFrame = new Rect(inputWindowHandle.frameLeft,
- inputWindowHandle.frameTop, inputWindowHandle.frameRight,
- inputWindowHandle.frameBottom);
+ final Rect windowFrame = new Rect(inputWindowHandle.frame);
getTouchableRegionInWindow(instance.mShouldMagnify, inputWindowHandle.touchableRegion,
instance.mTouchableRegionInWindow, windowFrame, magnificationInverseMatrix,
displayMatrix);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index cba215ad23fd..649ab8fe1d4d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4381,7 +4381,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Reset the last saved PiP snap fraction on removal.
mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
mDisplayContent.onRunningActivityChanged();
- mWmService.mEmbeddedWindowController.onActivityRemoved(this);
mRemovingFromDisplay = false;
}
@@ -7259,8 +7258,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void showStartingWindow(boolean taskSwitch) {
- showStartingWindow(null /* prev */, false /* newTask */, taskSwitch,
- false /* startActivity */, null);
+ // Pass the activity which contains starting window already.
+ final ActivityRecord prev = task.getActivity(
+ a -> a != this && a.mStartingData != null && a.showToCurrentUser());
+ showStartingWindow(prev, false /* newTask */, taskSwitch, false /* startActivity */, null);
}
/**
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 2eceeccd9d8f..025047588ea5 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -172,10 +172,9 @@ class AsyncRotationController extends FadeAnimationController implements Consume
if (recents != null && recents.isNavigationBarAttachedToApp()) {
return;
}
- } else if (navigationBarCanMove || mTransitionOp == OP_CHANGE_MAY_SEAMLESS) {
+ } else if (navigationBarCanMove || mTransitionOp == OP_CHANGE_MAY_SEAMLESS
+ || mDisplayContent.mTransitionController.mNavigationBarAttachedToApp) {
action = Operation.ACTION_SEAMLESS;
- } else if (mDisplayContent.mTransitionController.mNavigationBarAttachedToApp) {
- return;
}
mTargetWindowTokens.put(w.mToken, new Operation(action));
return;
@@ -294,6 +293,11 @@ class AsyncRotationController extends FadeAnimationController implements Consume
finishOp(mTargetWindowTokens.keyAt(i));
}
mTargetWindowTokens.clear();
+ onAllCompleted();
+ }
+
+ private void onAllCompleted() {
+ if (DEBUG) Slog.d(TAG, "onAllCompleted");
if (mTimeoutRunnable != null) {
mService.mH.removeCallbacks(mTimeoutRunnable);
}
@@ -333,7 +337,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
if (DEBUG) Slog.d(TAG, "Complete directly " + token.getTopChild());
finishOp(token);
if (mTargetWindowTokens.isEmpty()) {
- if (mTimeoutRunnable != null) mService.mH.removeCallbacks(mTimeoutRunnable);
+ onAllCompleted();
return true;
}
}
@@ -411,14 +415,18 @@ class AsyncRotationController extends FadeAnimationController implements Consume
if (mDisplayContent.mInputMethodWindow == null) return;
final WindowToken imeWindowToken = mDisplayContent.mInputMethodWindow.mToken;
if (isTargetToken(imeWindowToken)) return;
+ hideImmediately(imeWindowToken, Operation.ACTION_TOGGLE_IME);
+ if (DEBUG) Slog.d(TAG, "hideImeImmediately " + imeWindowToken.getTopChild());
+ }
+
+ private void hideImmediately(WindowToken token, @Operation.Action int action) {
final boolean original = mHideImmediately;
mHideImmediately = true;
- final Operation op = new Operation(Operation.ACTION_TOGGLE_IME);
- mTargetWindowTokens.put(imeWindowToken, op);
- fadeWindowToken(false /* show */, imeWindowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
- op.mLeash = imeWindowToken.getAnimationLeash();
+ final Operation op = new Operation(action);
+ mTargetWindowTokens.put(token, op);
+ fadeWindowToken(false /* show */, token, ANIMATION_TYPE_TOKEN_TRANSFORM);
+ op.mLeash = token.getAnimationLeash();
mHideImmediately = original;
- if (DEBUG) Slog.d(TAG, "hideImeImmediately " + imeWindowToken.getTopChild());
}
/** Returns {@code true} if the window will rotate independently. */
@@ -428,11 +436,20 @@ class AsyncRotationController extends FadeAnimationController implements Consume
|| isTargetToken(w.mToken);
}
- /** Returns {@code true} if the controller will run fade animations on the window. */
+ /**
+ * Returns {@code true} if the rotation transition appearance of the window is currently
+ * managed by this controller.
+ */
boolean isTargetToken(WindowToken token) {
return mTargetWindowTokens.containsKey(token);
}
+ /** Returns {@code true} if the controller will run fade animations on the window. */
+ boolean hasFadeOperation(WindowToken token) {
+ final Operation op = mTargetWindowTokens.get(token);
+ return op != null && op.mAction == Operation.ACTION_FADE;
+ }
+
/**
* Whether the insets animation leash should use previous position when running fade animation
* or seamless transformation in a rotated display.
@@ -564,7 +581,18 @@ class AsyncRotationController extends FadeAnimationController implements Consume
return false;
}
final Operation op = mTargetWindowTokens.get(w.mToken);
- if (op == null) return false;
+ if (op == null) {
+ // If a window becomes visible after the rotation transition is requested but before
+ // the transition is ready, hide it by an animation leash so it won't be flickering
+ // by drawing the rotated content before applying projection transaction of display.
+ // And it will fade in after the display transition is finished.
+ if (mTransitionOp == OP_APP_SWITCH && !mIsStartTransactionCommitted
+ && canBeAsync(w.mToken)) {
+ hideImmediately(w.mToken, Operation.ACTION_FADE);
+ if (DEBUG) Slog.d(TAG, "Hide on finishDrawing " + w.mToken.getTopChild());
+ }
+ return false;
+ }
if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
if (postDrawTransaction == null || !mIsSyncDrawRequested
|| canDrawBeforeStartTransaction(op)) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5c82dba82031..59677f41123a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -327,6 +327,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
private SurfaceControl mOverlayLayer;
+ /**
+ * A SurfaceControl that contains input overlays used for cases where we need to receive input
+ * over the entire display.
+ */
+ private SurfaceControl mInputOverlayLayer;
+
/** A surfaceControl specifically for accessibility overlays. */
private SurfaceControl mA11yOverlayLayer;
@@ -1327,6 +1333,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
transaction.reparent(mOverlayLayer, mSurfaceControl);
}
+ if (mInputOverlayLayer == null) {
+ mInputOverlayLayer = b.setName("Input Overlays").setParent(mSurfaceControl).build();
+ } else {
+ transaction.reparent(mInputOverlayLayer, mSurfaceControl);
+ }
+
if (mA11yOverlayLayer == null) {
mA11yOverlayLayer =
b.setName("Accessibility Overlays").setParent(mSurfaceControl).build();
@@ -1340,7 +1352,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
.show(mSurfaceControl)
.setLayer(mOverlayLayer, Integer.MAX_VALUE)
.show(mOverlayLayer)
- .setLayer(mA11yOverlayLayer, Integer.MAX_VALUE - 1)
+ .setLayer(mInputOverlayLayer, Integer.MAX_VALUE - 1)
+ .show(mInputOverlayLayer)
+ .setLayer(mA11yOverlayLayer, Integer.MAX_VALUE - 2)
.show(mA11yOverlayLayer);
}
@@ -3351,6 +3365,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// -> this DisplayContent.
setRemoteInsetsController(null);
mOverlayLayer.release();
+ mInputOverlayLayer.release();
mA11yOverlayLayer.release();
mWindowingLayer.release();
mInputMonitor.onDisplayRemoved();
@@ -5704,6 +5719,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mOverlayLayer;
}
+ SurfaceControl getInputOverlayLayer() {
+ return mInputOverlayLayer;
+ }
+
SurfaceControl getA11yOverlayLayer() {
return mA11yOverlayLayer;
}
@@ -7060,6 +7079,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
new Transaction().reparent(sc, getSurfaceControl())
.reparent(mWindowingLayer, null)
.reparent(mOverlayLayer, null)
+ .reparent(mInputOverlayLayer, null)
.reparent(mA11yOverlayLayer, null)
.apply();
}
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 98027bbed37f..c9bae127b800 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -135,19 +135,6 @@ class EmbeddedWindowController {
return mWindowsByWindowToken.get(windowToken);
}
- void onActivityRemoved(ActivityRecord activityRecord) {
- for (int i = mWindows.size() - 1; i >= 0; i--) {
- final EmbeddedWindow window = mWindows.valueAt(i);
- if (window.mHostActivityRecord == activityRecord) {
- final WindowProcessController processController =
- mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
- if (processController != null) {
- processController.removeHostActivity(activityRecord);
- }
- }
- }
- }
-
static class EmbeddedWindow implements InputTarget {
final IWindow mClient;
@Nullable final WindowState mHostWindowState;
@@ -230,6 +217,13 @@ class EmbeddedWindowController {
mInputChannel.dispose();
mInputChannel = null;
}
+ if (mHostActivityRecord != null) {
+ final WindowProcessController wpc =
+ mWmService.mAtmService.getProcessController(mOwnerPid, mOwnerUid);
+ if (wpc != null) {
+ wpc.removeHostActivity(mHostActivityRecord);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 73fdfe0d1181..8cf471394c63 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -275,11 +275,17 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
+ " - DisplayContent not found.");
return null;
}
+ final SurfaceControl inputOverlay = dc.getInputOverlayLayer();
+ if (inputOverlay == null) {
+ Slog.e(TAG, "Failed to create a gesture monitor on display: " + displayId
+ + " - Input overlay layer is not initialized.");
+ return null;
+ }
return mService.makeSurfaceBuilder(dc.getSession())
.setContainerLayer()
.setName(name)
.setCallsite("createSurfaceForGestureMonitor")
- .setParent(dc.getSurfaceControl())
+ .setParent(inputOverlay)
.build();
}
}
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
index 3d4e0ebac258..64b7a6064e45 100644
--- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -227,18 +227,6 @@ class InputWindowHandleWrapper {
mChanged = true;
}
- void setFrame(int left, int top, int right, int bottom) {
- if (mHandle.frameLeft == left && mHandle.frameTop == top && mHandle.frameRight == right
- && mHandle.frameBottom == bottom) {
- return;
- }
- mHandle.frameLeft = left;
- mHandle.frameTop = top;
- mHandle.frameRight = right;
- mHandle.frameBottom = bottom;
- mChanged = true;
- }
-
void setSurfaceInset(int inset) {
if (mHandle.surfaceInset == inset) {
return;
diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
index 2e5474e5e415..79b26d2ee994 100644
--- a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
@@ -86,7 +86,7 @@ public class NavBarFadeAnimationController extends FadeAnimationController{
ANIMATION_TYPE_TOKEN_TRANSFORM);
if (controller == null) {
fadeAnim.run();
- } else if (!controller.isTargetToken(mNavigationBar.mToken)) {
+ } else if (!controller.hasFadeOperation(mNavigationBar.mToken)) {
// If fade rotation animation is running and the nav bar is not controlled by it:
// - For fade-in animation, defer the animation until fade rotation animation finishes.
// - For fade-out animation, just play the animation.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 237846997e9e..def32a1bda87 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -40,6 +40,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -546,7 +547,7 @@ public class RecentsAnimationController implements DeathRecipient {
contentInsets = mTmpRect;
}
mRunner.onAnimationStart(mController, appTargets, wallpaperTargets, contentInsets,
- null);
+ null, new Bundle());
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"startAnimation(): Notify animation start: %s",
mPendingAnimations.stream()
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 43430dd1eed0..f9bbc6810835 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -725,7 +725,7 @@ class Task extends TaskFragment {
} catch (RemoteException e) {
}
}
- if (autoRemoveFromRecents(oldParent.asTaskFragment()) || isVoiceSession) {
+ if (shouldAutoRemoveFromRecents(oldParent.asTaskFragment()) || isVoiceSession) {
// Task creator asked to remove this when done, or this task was a voice
// interaction, so it should not remain on the recent tasks list.
mTaskSupervisor.mRecentTasks.remove(this);
@@ -1558,12 +1558,14 @@ class Task extends TaskFragment {
return count > 0;
}
- private boolean autoRemoveFromRecents(TaskFragment oldParentFragment) {
+ private boolean shouldAutoRemoveFromRecents(TaskFragment oldParentFragment) {
// We will automatically remove the task either if it has explicitly asked for
// this, or it is empty and has never contained an activity that got shown to
- // the user, or it was being embedded in another Task.
- return autoRemoveRecents || (!hasChild() && !getHasBeenVisible()
- || (oldParentFragment != null && oldParentFragment.isEmbedded()));
+ // the user, or it was being embedded in another Task, or the display policy
+ // doesn't allow recents,
+ return autoRemoveRecents || (!hasChild() && !getHasBeenVisible())
+ || (oldParentFragment != null && oldParentFragment.isEmbedded())
+ || (mDisplayContent != null && !mDisplayContent.canShowTasksInHostDeviceRecents());
}
private void clearPinnedTaskIfNeed() {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 1566bb2c8610..e9af42bb7b90 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1930,11 +1930,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
break;
}
- final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
- if (asyncRotationController != null) {
- asyncRotationController.accept(navWindow);
- }
-
if (animate) {
final NavBarFadeAnimationController controller =
new NavBarFadeAnimationController(dc);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 6432ff081c73..6ede3456d74c 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -1124,14 +1124,15 @@ class TransitionController {
+ "track #%d", transition.getSyncId(), track);
}
}
- if (sync) {
+ transition.mAnimationTrack = track;
+ info.setTrack(track);
+ mTrackCount = Math.max(mTrackCount, track + 1);
+ if (sync && mTrackCount > 1) {
+ // If there are >1 tracks, mark as sync so that all tracks finish.
info.setFlags(info.getFlags() | TransitionInfo.FLAG_SYNC);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Marking #%d animation as SYNC.",
transition.getSyncId());
}
- transition.mAnimationTrack = track;
- info.setTrack(track);
- mTrackCount = Math.max(mTrackCount, track + 1);
}
void updateAnimatingState(SurfaceControl.Transaction t) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 03efb1bf705e..439b7193dd4b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8338,12 +8338,18 @@ public class WindowManagerService extends IWindowManager.Stub
+ displayId + " - DisplayContent not found.");
return null;
}
- //TODO (b/210039666): Use a method like add/removeDisplayOverlay if available.
+ final SurfaceControl inputOverlay = dc.getInputOverlayLayer();
+ if (inputOverlay == null) {
+ Slog.e(TAG, "Failed to create a gesture monitor on display: " + displayId
+ + " - Input overlay layer is not initialized.");
+ return null;
+ }
+ // TODO(b/210039666): Use a method like add/removeDisplayOverlay if available.
return makeSurfaceBuilder(dc.getSession())
.setContainerLayer()
.setName("IME Handwriting Surface")
.setCallsite("getHandwritingSurfaceForDisplay")
- .setParent(dc.getSurfaceControl())
+ .setParent(inputOverlay)
.build();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5a45fe11797e..a172d9912cbd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -30,7 +30,6 @@ import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.SurfaceControl.Transaction;
import static android.view.SurfaceControl.getGlobalTransaction;
-import static android.view.ViewRootImpl.LOCAL_LAYOUT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -1446,9 +1445,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
final boolean dragResizingChanged = !mDragResizingChangeReported && isDragResizeChanged();
-
- final boolean attachedFrameChanged = LOCAL_LAYOUT
- && mLayoutAttached && getParentWindow().frameChanged();
+ final boolean attachedFrameChanged = mLayoutAttached && getParentWindow().frameChanged();
if (DEBUG) {
Slog.v(TAG_WM, "Resizing " + this + ": configChanged=" + configChanged
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 405b133a6de1..2f150a12dbf0 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -50,6 +50,7 @@ cc_library_static {
"com_android_server_locksettings_SyntheticPasswordManager.cpp",
"com_android_server_power_PowerManagerService.cpp",
"com_android_server_powerstats_PowerStatsService.cpp",
+ "com_android_server_power_stats_CpuPowerStatsCollector.cpp",
"com_android_server_hint_HintManagerService.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
@@ -144,6 +145,7 @@ cc_defaults {
"libsensorservicehidl",
"libsensorserviceaidl",
"libgui",
+ "libtimeinstate",
"libtimestats_atoms_proto",
"libusbhost",
"libtinyalsa",
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index d9acf4182736..7e8ce60b8a50 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -23,6 +23,7 @@ per-file com_android_server_net_* = file:/services/core/java/com/android/server/
per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS
per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS
per-file com_android_server_powerstats_* = file:/services/core/java/com/android/server/powerstats/OWNERS
+per-file com_android_server_power_stats_* = file:/BATTERY_STATS_OWNERS
per-file com_android_server_security_* = file:/core/java/android/security/OWNERS
per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS
per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index cfc63f0a0896..7b084132ed1c 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -54,6 +54,9 @@ using android::base::WriteStringToFile;
using android::meminfo::ProcMemInfo;
using namespace android::meminfo;
+static const size_t kPageSize = getpagesize();
+static const size_t kPageMask = ~(kPageSize - 1);
+
#define COMPACT_ACTION_FILE_FLAG 1
#define COMPACT_ACTION_ANON_FLAG 2
@@ -64,7 +67,7 @@ using android::base::unique_fd;
#define ASYNC_RECEIVED_WHILE_FROZEN (2)
#define TXNS_PENDING_WHILE_FROZEN (4)
-#define MAX_RW_COUNT (INT_MAX & PAGE_MASK)
+#define MAX_RW_COUNT (INT_MAX & kPageMask)
// Defines the maximum amount of VMAs we can send per process_madvise syscall.
// Currently this is set to UIO_MAXIOV which is the maximum segments allowed by
@@ -233,7 +236,6 @@ public:
// process_madvise on failure
int madviseVmasFromBatch(unique_fd& pidfd, VmaBatch& batch, int madviseType,
uint64_t* outBytesProcessed) {
- static const size_t kPageSize = getpagesize();
if (batch.totalVmas == 0 || batch.totalBytes == 0) {
// No VMAs in Batch, skip.
*outBytesProcessed = 0;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 7c8c558474bb..5ab8d362ce91 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -400,7 +400,7 @@ private:
PointerCaptureRequest pointerCaptureRequest{};
// Sprite controller singleton, created on first use.
- sp<SpriteController> spriteController{};
+ std::shared_ptr<SpriteController> spriteController{};
// Pointer controller singleton, created and destroyed as needed.
std::weak_ptr<PointerController> pointerController{};
@@ -709,7 +709,7 @@ std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerCon
if (controller == nullptr) {
ensureSpriteControllerLocked();
- controller = PointerController::create(this, mLooper, mLocked.spriteController);
+ controller = PointerController::create(this, mLooper, *mLocked.spriteController);
mLocked.pointerController = controller;
updateInactivityTimeoutLocked();
}
@@ -738,16 +738,21 @@ sp<SurfaceControl> NativeInputManager::getParentSurfaceForPointers(int displayId
}
void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) {
- if (mLocked.spriteController == nullptr) {
- JNIEnv* env = jniEnv();
- jint layer = env->CallIntMethod(mServiceObj, gServiceClassInfo.getPointerLayer);
- if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) {
- layer = -1;
- }
- mLocked.spriteController = new SpriteController(mLooper, layer, [this](int displayId) {
- return getParentSurfaceForPointers(displayId);
- });
+ if (mLocked.spriteController) {
+ return;
}
+ JNIEnv* env = jniEnv();
+ jint layer = env->CallIntMethod(mServiceObj, gServiceClassInfo.getPointerLayer);
+ if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) {
+ layer = -1;
+ }
+ mLocked.spriteController =
+ std::make_shared<SpriteController>(mLooper, layer, [this](int displayId) {
+ return getParentSurfaceForPointers(displayId);
+ });
+ // The SpriteController needs to be shared pointer because the handler callback needs to hold
+ // a weak reference so that we can avoid racy conditions when the controller is being destroyed.
+ mLocked.spriteController->setHandlerController(mLocked.spriteController);
}
void NativeInputManager::notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
diff --git a/services/core/jni/com_android_server_power_stats_CpuPowerStatsCollector.cpp b/services/core/jni/com_android_server_power_stats_CpuPowerStatsCollector.cpp
new file mode 100644
index 000000000000..a6084ea17806
--- /dev/null
+++ b/services/core/jni/com_android_server_power_stats_CpuPowerStatsCollector.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CpuPowerStatsCollector"
+
+#include <cputimeinstate.h>
+#include <log/log.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+
+#include "core_jni_helpers.h"
+
+#define EXCEPTION (-1)
+
+namespace android {
+
+#define JAVA_CLASS_CPU_POWER_STATS_COLLECTOR "com/android/server/power/stats/CpuPowerStatsCollector"
+#define JAVA_CLASS_KERNEL_CPU_STATS_READER \
+ JAVA_CLASS_CPU_POWER_STATS_COLLECTOR "$KernelCpuStatsReader"
+#define JAVA_CLASS_KERNEL_CPU_STATS_CALLBACK \
+ JAVA_CLASS_CPU_POWER_STATS_COLLECTOR "$KernelCpuStatsCallback"
+
+static constexpr uint64_t NSEC_PER_MSEC = 1000000;
+
+static int extractUidStats(JNIEnv *env, std::vector<std::vector<uint64_t>> &times,
+ ScopedIntArrayRO &scopedScalingStepToPowerBracketMap,
+ jlongArray tempForUidStats);
+
+static bool initialized = false;
+static jclass class_KernelCpuStatsCallback;
+static jmethodID method_KernelCpuStatsCallback_processUidStats;
+
+static int init(JNIEnv *env) {
+ jclass temp = env->FindClass(JAVA_CLASS_KERNEL_CPU_STATS_CALLBACK);
+ class_KernelCpuStatsCallback = (jclass)env->NewGlobalRef(temp);
+ if (!class_KernelCpuStatsCallback) {
+ jniThrowExceptionFmt(env, "java/lang/ClassNotFoundException",
+ "Class not found: " JAVA_CLASS_KERNEL_CPU_STATS_CALLBACK);
+ return EXCEPTION;
+ }
+ method_KernelCpuStatsCallback_processUidStats =
+ env->GetMethodID(class_KernelCpuStatsCallback, "processUidStats", "(I[J)V");
+ if (!method_KernelCpuStatsCallback_processUidStats) {
+ jniThrowExceptionFmt(env, "java/lang/NoSuchMethodException",
+ "Method not found: " JAVA_CLASS_KERNEL_CPU_STATS_CALLBACK
+ ".processUidStats");
+ return EXCEPTION;
+ }
+ initialized = true;
+ return OK;
+}
+
+static jlong nativeReadCpuStats(JNIEnv *env, [[maybe_unused]] jobject zis, jobject callback,
+ jintArray scalingStepToPowerBracketMap,
+ jlong lastUpdateTimestampNanos, jlongArray tempForUidStats) {
+ if (!initialized) {
+ if (init(env) == EXCEPTION) {
+ return 0L;
+ }
+ }
+
+ uint64_t newLastUpdate = lastUpdateTimestampNanos;
+ auto data = android::bpf::getUidsUpdatedCpuFreqTimes(&newLastUpdate);
+ if (!data.has_value()) return lastUpdateTimestampNanos;
+
+ ScopedIntArrayRO scopedScalingStepToPowerBracketMap(env, scalingStepToPowerBracketMap);
+
+ for (auto &[uid, times] : *data) {
+ int status =
+ extractUidStats(env, times, scopedScalingStepToPowerBracketMap, tempForUidStats);
+ if (status == EXCEPTION) {
+ return 0L;
+ }
+ env->CallVoidMethod(callback, method_KernelCpuStatsCallback_processUidStats, (jint)uid,
+ tempForUidStats);
+ }
+ return newLastUpdate;
+}
+
+static int extractUidStats(JNIEnv *env, std::vector<std::vector<uint64_t>> &times,
+ ScopedIntArrayRO &scopedScalingStepToPowerBracketMap,
+ jlongArray tempForUidStats) {
+ ScopedLongArrayRW scopedTempForStats(env, tempForUidStats);
+ uint64_t *arrayForStats = reinterpret_cast<uint64_t *>(scopedTempForStats.get());
+ const uint8_t statsSize = scopedTempForStats.size();
+ memset(arrayForStats, 0, statsSize * sizeof(uint64_t));
+ const uint8_t scalingStepCount = scopedScalingStepToPowerBracketMap.size();
+
+ uint32_t scalingStep = 0;
+ for (const auto &subVec : times) {
+ for (uint32_t i = 0; i < subVec.size(); ++i) {
+ if (scalingStep >= scalingStepCount) {
+ jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
+ "scalingStepToPowerBracketMap is too short, "
+ "size=%u, scalingStep=%u",
+ scalingStepCount, scalingStep);
+ return EXCEPTION;
+ }
+ uint32_t bucket = scopedScalingStepToPowerBracketMap[scalingStep];
+ if (bucket >= statsSize) {
+ jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
+ "UidStats array is too short, length=%u, bucket[%u]=%u",
+ statsSize, scalingStep, bucket);
+ return EXCEPTION;
+ }
+ arrayForStats[bucket] += subVec[i] / NSEC_PER_MSEC;
+ scalingStep++;
+ }
+ }
+ return OK;
+}
+
+static const JNINativeMethod method_table[] = {
+ {"nativeReadCpuStats", "(L" JAVA_CLASS_KERNEL_CPU_STATS_CALLBACK ";[IJ[J)J",
+ (void *)nativeReadCpuStats},
+};
+
+int register_android_server_power_stats_CpuPowerStatsCollector(JNIEnv *env) {
+ return jniRegisterNativeMethods(env, JAVA_CLASS_KERNEL_CPU_STATS_READER, method_table,
+ NELEM(method_table));
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 290ad8de9547..97d7be6a718e 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -30,6 +30,7 @@ int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_PowerStatsService(JNIEnv* env);
+int register_android_server_power_stats_CpuPowerStatsCollector(JNIEnv* env);
int register_android_server_HintManagerService(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
@@ -85,6 +86,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_broadcastradio_Tuner(vm, env);
register_android_server_PowerManagerService(env);
register_android_server_PowerStatsService(env);
+ register_android_server_power_stats_CpuPowerStatsCollector(env);
register_android_server_HintManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputManager(env);
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 17474fbe1de4..6a349e237ffe 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -26,6 +26,7 @@ import com.android.server.permission.access.collection.* // ktlint-disable no-wi
import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.immutable.IndexedMap
import com.android.server.permission.access.permission.AppIdPermissionPolicy
+import com.android.server.permission.access.permission.DevicePermissionPolicy
import com.android.server.permission.access.util.attributeInt
import com.android.server.permission.access.util.attributeInterned
import com.android.server.permission.access.util.forEachTag
@@ -46,6 +47,7 @@ class AccessPolicy private constructor(
getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] = policy
}
addPolicy(AppIdPermissionPolicy())
+ addPolicy(DevicePermissionPolicy())
addPolicy(AppIdAppOpPolicy())
addPolicy(PackageAppOpPolicy())
} as IndexedMap<String, IndexedMap<String, SchemePolicy>>
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index 4ec32ea53f28..94c878a453c9 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -329,6 +329,18 @@ typealias MutableAppIdPermissionFlags =
private typealias AppIdPermissionFlagsReference =
MutableReference<AppIdPermissionFlags, MutableAppIdPermissionFlags>
+
+typealias DevicePermissionFlags =
+ IndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+typealias MutableDevicePermissionFlags =
+ MutableIndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
+typealias AppIdDevicePermissionFlags =
+ IntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
+typealias MutableAppIdDevicePermissionFlags =
+ MutableIntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
+private typealias AppIdDevicePermissionFlagsReference =
+ MutableReference<AppIdDevicePermissionFlags, MutableAppIdDevicePermissionFlags>
+
typealias AppIdAppOpModes =
IntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
typealias MutableAppIdAppOpModes =
@@ -346,6 +358,7 @@ private typealias PackageAppOpModesReference =
sealed class UserState(
internal val packageVersionsReference: PackageVersionsReference,
internal val appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
+ internal val appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
internal val appIdAppOpModesReference: AppIdAppOpModesReference,
internal val packageAppOpModesReference: PackageAppOpModesReference,
defaultPermissionGrantFingerprint: String?,
@@ -357,6 +370,9 @@ sealed class UserState(
val appIdPermissionFlags: AppIdPermissionFlags
get() = appIdPermissionFlagsReference.get()
+ val appIdDevicePermissionFlags: AppIdDevicePermissionFlags
+ get() = appIdDevicePermissionFlagsReference.get()
+
val appIdAppOpModes: AppIdAppOpModes
get() = appIdAppOpModesReference.get()
@@ -375,6 +391,7 @@ sealed class UserState(
class MutableUserState private constructor(
packageVersionsReference: PackageVersionsReference,
appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
+ appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
appIdAppOpModesReference: AppIdAppOpModesReference,
packageAppOpModesReference: PackageAppOpModesReference,
defaultPermissionGrantFingerprint: String?,
@@ -382,6 +399,7 @@ class MutableUserState private constructor(
) : UserState(
packageVersionsReference,
appIdPermissionFlagsReference,
+ appIdDevicePermissionFlagsReference,
appIdAppOpModesReference,
packageAppOpModesReference,
defaultPermissionGrantFingerprint,
@@ -390,6 +408,7 @@ class MutableUserState private constructor(
constructor() : this(
PackageVersionsReference(MutableIndexedMap<String, Int>()),
AppIdPermissionFlagsReference(MutableAppIdPermissionFlags()),
+ AppIdDevicePermissionFlagsReference(MutableAppIdDevicePermissionFlags()),
AppIdAppOpModesReference(MutableAppIdAppOpModes()),
PackageAppOpModesReference(MutablePackageAppOpModes()),
null,
@@ -399,6 +418,7 @@ class MutableUserState private constructor(
internal constructor(userState: UserState) : this(
userState.packageVersionsReference.toImmutable(),
userState.appIdPermissionFlagsReference.toImmutable(),
+ userState.appIdDevicePermissionFlagsReference.toImmutable(),
userState.appIdAppOpModesReference.toImmutable(),
userState.packageAppOpModesReference.toImmutable(),
userState.defaultPermissionGrantFingerprint,
@@ -410,6 +430,9 @@ class MutableUserState private constructor(
fun mutateAppIdPermissionFlags(): MutableAppIdPermissionFlags =
appIdPermissionFlagsReference.mutate()
+ fun mutateAppIdDevicePermissionFlags(): MutableAppIdDevicePermissionFlags =
+ appIdDevicePermissionFlagsReference.mutate()
+
fun mutateAppIdAppOpModes(): MutableAppIdAppOpModes = appIdAppOpModesReference.mutate()
fun mutatePackageAppOpModes(): MutablePackageAppOpModes = packageAppOpModesReference.mutate()
diff --git a/services/permission/java/com/android/server/permission/access/AccessUri.kt b/services/permission/java/com/android/server/permission/access/AccessUri.kt
index d1abc0455245..1d46ca71fe0f 100644
--- a/services/permission/java/com/android/server/permission/access/AccessUri.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessUri.kt
@@ -65,6 +65,17 @@ data class PermissionUri(
}
}
+data class DevicePermissionUri(
+ val permissionName: String,
+ val deviceId: Int
+) : AccessUri(SCHEME) {
+ override fun toString(): String = "$scheme:///$permissionName/$deviceId"
+
+ companion object {
+ const val SCHEME = "device-permission"
+ }
+}
+
data class UidUri(
val uid: Int
) : AccessUri(SCHEME) {
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
new file mode 100644
index 000000000000..37a4a90f8f80
--- /dev/null
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.permission.access.permission
+
+import android.util.Slog
+import com.android.modules.utils.BinaryXmlPullParser
+import com.android.modules.utils.BinaryXmlSerializer
+import com.android.server.permission.access.AccessState
+import com.android.server.permission.access.DevicePermissionFlags
+import com.android.server.permission.access.MutableAccessState
+import com.android.server.permission.access.MutableAppIdDevicePermissionFlags
+import com.android.server.permission.access.MutableDevicePermissionFlags
+import com.android.server.permission.access.WriteMode
+import com.android.server.permission.access.immutable.IndexedMap
+import com.android.server.permission.access.immutable.MutableIndexedMap
+import com.android.server.permission.access.immutable.forEachIndexed
+import com.android.server.permission.access.immutable.forEachReversedIndexed
+import com.android.server.permission.access.immutable.set
+import com.android.server.permission.access.util.andInv
+import com.android.server.permission.access.util.attributeInt
+import com.android.server.permission.access.util.attributeInterned
+import com.android.server.permission.access.util.forEachTag
+import com.android.server.permission.access.util.getAttributeIntOrThrow
+import com.android.server.permission.access.util.getAttributeValueOrThrow
+import com.android.server.permission.access.util.hasBits
+import com.android.server.permission.access.util.tag
+import com.android.server.permission.access.util.tagName
+
+class DevicePermissionPersistence {
+ fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
+ when (tagName) {
+ TAG_APP_ID_DEVICE_PERMISSIONS -> parseAppIdDevicePermissions(state, userId)
+ else -> {}
+ }
+ }
+
+ private fun BinaryXmlPullParser.parseAppIdDevicePermissions(
+ state: MutableAccessState,
+ userId: Int
+ ) {
+ val userState = state.mutateUserState(userId, WriteMode.NONE)!!
+ val appIdDevicePermissionFlags = userState.mutateAppIdDevicePermissionFlags()
+ forEachTag {
+ when (tagName) {
+ TAG_APP_ID -> parseAppId(appIdDevicePermissionFlags)
+ else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
+ }
+ }
+
+ appIdDevicePermissionFlags.forEachReversedIndexed { appIdIndex, appId, _ ->
+ if (appId !in state.externalState.appIdPackageNames) {
+ Slog.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state")
+ appIdDevicePermissionFlags.removeAt(appIdIndex)
+ userState.requestWriteMode(WriteMode.ASYNCHRONOUS)
+ }
+ }
+ }
+
+ private fun BinaryXmlPullParser.parseAppId(
+ appIdPermissionFlags: MutableAppIdDevicePermissionFlags
+ ) {
+ val appId = getAttributeIntOrThrow(ATTR_ID)
+ val devicePermissionFlags = MutableDevicePermissionFlags()
+ appIdPermissionFlags[appId] = devicePermissionFlags
+ forEachTag {
+ when (tagName) {
+ TAG_DEVICE -> parseDevice(devicePermissionFlags)
+ else -> {
+ Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
+ }
+ }
+ }
+ }
+
+ private fun BinaryXmlPullParser.parseDevice(
+ deviceIdPermissionFlags: MutableDevicePermissionFlags
+ ) {
+ val deviceId = getAttributeValueOrThrow(ATTR_ID)
+ val permissionFlags = MutableIndexedMap<String, Int>()
+ deviceIdPermissionFlags.put(deviceId, permissionFlags)
+ forEachTag {
+ when (tagName) {
+ TAG_PERMISSION -> parsePermission(permissionFlags)
+ else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
+ }
+ }
+ }
+
+ private fun BinaryXmlPullParser.parsePermission(
+ permissionFlags: MutableIndexedMap<String, Int>
+ ) {
+ val name = getAttributeValueOrThrow(ATTR_NAME).intern()
+ val flags = getAttributeIntOrThrow(ATTR_FLAGS)
+ permissionFlags[name] = flags
+ }
+
+ fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
+ val appIdDevicePermissionFlags = state.userStates[userId]!!.appIdDevicePermissionFlags
+ tag(TAG_APP_ID_DEVICE_PERMISSIONS) {
+ appIdDevicePermissionFlags.forEachIndexed { _, appId, devicePermissionFlags ->
+ serializeAppId(appId, devicePermissionFlags)
+ }
+ }
+ }
+
+ private fun BinaryXmlSerializer.serializeAppId(
+ appId: Int,
+ devicePermissionFlags: DevicePermissionFlags
+ ) {
+ tag(TAG_APP_ID) {
+ attributeInt(ATTR_ID, appId)
+ devicePermissionFlags.forEachIndexed { _, deviceId, permissionFlags ->
+ serializeDevice(deviceId, permissionFlags)
+ }
+ }
+ }
+
+ private fun BinaryXmlSerializer.serializeDevice(
+ deviceId: String,
+ permissionFlags: IndexedMap<String, Int>
+ ) {
+ tag(TAG_DEVICE) {
+ attributeInterned(ATTR_ID, deviceId)
+ permissionFlags.forEachIndexed { _, name, flags ->
+ serializePermission(name, flags)
+ }
+ }
+ }
+
+ private fun BinaryXmlSerializer.serializePermission(name: String, flags: Int) {
+ tag(TAG_PERMISSION) {
+ attributeInterned(ATTR_NAME, name)
+ // Never serialize one-time permissions as granted.
+ val serializedFlags = if (flags.hasBits(PermissionFlags.ONE_TIME)) {
+ flags andInv PermissionFlags.RUNTIME_GRANTED
+ } else {
+ flags
+ }
+ attributeInt(ATTR_FLAGS, serializedFlags)
+ }
+ }
+
+ companion object {
+ private val LOG_TAG = DevicePermissionPersistence::class.java.simpleName
+
+ private const val TAG_APP_ID_DEVICE_PERMISSIONS = "app-id-device-permissions"
+ private const val TAG_APP_ID = "app-id"
+ private const val TAG_DEVICE = "device"
+ private const val TAG_PERMISSION = "permission"
+
+ private const val ATTR_ID = "id"
+ private const val ATTR_NAME = "name"
+ private const val ATTR_FLAGS = "flags"
+ }
+} \ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
new file mode 100644
index 000000000000..c0d7546180bf
--- /dev/null
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.permission.access.permission
+
+import android.util.Slog
+import com.android.modules.utils.BinaryXmlPullParser
+import com.android.modules.utils.BinaryXmlSerializer
+import com.android.server.permission.access.AccessState
+import com.android.server.permission.access.DevicePermissionUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutableAccessState
+import com.android.server.permission.access.MutateStateScope
+import com.android.server.permission.access.SchemePolicy
+import com.android.server.permission.access.UidUri
+import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
+import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
+import com.android.server.permission.access.util.andInv
+import com.android.server.pm.pkg.PackageState
+
+class DevicePermissionPolicy : SchemePolicy() {
+ private val persistence = DevicePermissionPersistence()
+
+ @Volatile
+ private var listeners: IndexedListSet<OnDevicePermissionFlagsChangedListener> =
+ MutableIndexedListSet()
+ private val listenersLock = Any()
+
+ override val subjectScheme: String
+ get() = UidUri.SCHEME
+
+ override val objectScheme: String
+ get() = DevicePermissionUri.SCHEME
+
+ override fun GetStateScope.onStateMutated() {
+ listeners.forEachIndexed { _, it -> it.onStateMutated() }
+ }
+
+ override fun MutateStateScope.onAppIdRemoved(appId: Int) {
+ newState.userStates.forEachIndexed { userStateIndex, _, userState ->
+ if (appId in userState.appIdDevicePermissionFlags) {
+ newState.mutateUserStateAt(userStateIndex)
+ .mutateAppIdDevicePermissionFlags() -= appId
+ }
+ }
+ }
+
+ override fun MutateStateScope.onStorageVolumeMounted(
+ volumeUuid: String?,
+ packageNames: List<String>,
+ isSystemUpdated: Boolean
+ ) {
+ packageNames.forEachIndexed { _, packageName ->
+ val packageState = newState.externalState.packageStates[packageName]!!
+ trimPermissionStates(packageState.appId)
+ }
+ }
+
+ override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
+ trimPermissionStates(packageState.appId)
+ }
+
+ override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
+ if (appId in newState.externalState.appIdPackageNames) {
+ trimPermissionStates(appId)
+ }
+ }
+
+ override fun MutateStateScope.onPackageUninstalled(
+ packageName: String,
+ appId: Int,
+ userId: Int
+ ) {
+ resetPermissionStates(packageName, userId)
+ }
+
+ private fun MutateStateScope.resetPermissionStates(packageName: String, userId: Int) {
+ // It's okay to skip resetting permissions for packages that are removed,
+ // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
+ val packageState = newState.externalState.packageStates[packageName] ?: return
+ val androidPackage = packageState.androidPackage ?: return
+ val appId = packageState.appId
+ val appIdPermissionFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags
+ androidPackage.requestedPermissions.forEach { permissionName ->
+ val isRequestedByOtherPackages = anyPackageInAppId(appId) {
+ it.packageName != packageName &&
+ permissionName in it.androidPackage!!.requestedPermissions
+ }
+ if (isRequestedByOtherPackages) {
+ return@forEach
+ }
+ appIdPermissionFlags[appId]?.forEachIndexed { _, deviceId, _ ->
+ setPermissionFlags(appId, deviceId, userId, permissionName, 0)
+ }
+ }
+ }
+
+ private fun MutateStateScope.trimPermissionStates(appId: Int) {
+ val requestedPermissions = MutableIndexedSet<String>()
+ forEachPackageInAppId(appId) {
+ requestedPermissions += it.androidPackage!!.requestedPermissions
+ }
+ newState.userStates.forEachIndexed { _, userId, userState ->
+ userState.appIdDevicePermissionFlags[appId]?.forEachReversedIndexed {
+ _, deviceId, permissionFlags ->
+ permissionFlags.forEachReversedIndexed { _, permissionName, _ ->
+ if (permissionName !in requestedPermissions) {
+ setPermissionFlags(appId, deviceId, userId, permissionName, 0)
+ }
+ }
+ }
+ }
+ }
+
+ private inline fun MutateStateScope.anyPackageInAppId(
+ appId: Int,
+ state: AccessState = newState,
+ predicate: (PackageState) -> Boolean
+ ): Boolean {
+ val packageNames = state.externalState.appIdPackageNames[appId]!!
+ return packageNames.anyIndexed { _, packageName ->
+ val packageState = state.externalState.packageStates[packageName]!!
+ packageState.androidPackage != null && predicate(packageState)
+ }
+ }
+
+ private inline fun MutateStateScope.forEachPackageInAppId(
+ appId: Int,
+ state: AccessState = newState,
+ action: (PackageState) -> Unit
+ ) {
+ val packageNames = state.externalState.appIdPackageNames[appId]!!
+ packageNames.forEachIndexed { _, packageName ->
+ val packageState = state.externalState.packageStates[packageName]!!
+ if (packageState.androidPackage != null) {
+ action(packageState)
+ }
+ }
+ }
+
+ override fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
+ with(persistence) { this@parseUserState.parseUserState(state, userId) }
+ }
+
+ override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
+ with(persistence) { this@serializeUserState.serializeUserState(state, userId) }
+ }
+
+ fun GetStateScope.getPermissionFlags(
+ appId: Int,
+ deviceId: String,
+ userId: Int,
+ permissionName: String
+ ): Int =
+ state.userStates[userId]?.appIdDevicePermissionFlags?.get(appId)?.get(deviceId)
+ ?.getWithDefault(permissionName, 0) ?: 0
+
+ fun MutateStateScope.setPermissionFlags(
+ appId: Int,
+ deviceId: String,
+ userId: Int,
+ permissionName: String,
+ flags: Int
+ ): Boolean =
+ updatePermissionFlags(
+ appId, deviceId, userId, permissionName, PermissionFlags.MASK_ALL, flags
+ )
+
+ private fun MutateStateScope.updatePermissionFlags(
+ appId: Int,
+ deviceId: String,
+ userId: Int,
+ permissionName: String,
+ flagMask: Int,
+ flagValues: Int
+ ): Boolean {
+ if (!isDeviceAwarePermission(permissionName)) {
+ Slog.w(LOG_TAG, "$permissionName is not a device aware permission.")
+ return false
+ }
+ val oldFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags[appId]
+ ?.get(deviceId).getWithDefault(permissionName, 0)
+ val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
+ if (oldFlags == newFlags) {
+ return false
+ }
+ val appIdDevicePermissionFlags =
+ newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
+ val devicePermissionFlags = appIdDevicePermissionFlags.mutateOrPut(appId) {
+ MutableIndexedReferenceMap()
+ }
+ val permissionFlags = devicePermissionFlags.mutateOrPut(deviceId) { MutableIndexedMap() }
+ permissionFlags.putWithDefault(permissionName, newFlags, 0)
+ if (permissionFlags.isEmpty()) {
+ devicePermissionFlags -= deviceId
+ if (devicePermissionFlags.isEmpty()) {
+ appIdDevicePermissionFlags -= appId
+ }
+ }
+ listeners.forEachIndexed { _, it ->
+ it.onDevicePermissionFlagsChanged(
+ appId, userId, deviceId, permissionName, oldFlags, newFlags
+ )
+ }
+ return true
+ }
+
+ fun addOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
+ synchronized(listenersLock) {
+ listeners = listeners + listener
+ }
+ }
+
+ fun removeOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
+ synchronized(listenersLock) {
+ listeners = listeners - listener
+ }
+ }
+
+ private fun isDeviceAwarePermission(permissionName: String): Boolean =
+ DEVICE_SUPPORTED_PERMISSIONS.contains(permissionName)
+
+ companion object {
+ private val LOG_TAG = DevicePermissionPolicy::class.java.simpleName
+
+ /**
+ * These permissions are supported for virtual devices.
+ */
+ private val DEVICE_SUPPORTED_PERMISSIONS = indexedSetOf(
+ android.Manifest.permission.CAMERA,
+ android.Manifest.permission.RECORD_AUDIO
+ )
+ }
+
+ /**
+ * TODO: b/289355341 - implement listener for permission changes
+ * Listener for permission flags changes.
+ */
+ abstract class OnDevicePermissionFlagsChangedListener {
+ /**
+ * Called when a permission flags change has been made to the upcoming new state.
+ *
+ * Implementations should keep this method fast to avoid stalling the locked state mutation,
+ * and only call external code after [onStateMutated] when the new state has actually become
+ * the current state visible to external code.
+ */
+ abstract fun onDevicePermissionFlagsChanged(
+ appId: Int,
+ userId: Int,
+ deviceId: String,
+ permissionName: String,
+ oldFlags: Int,
+ newFlags: Int
+ )
+
+ /**
+ * Called when the upcoming new state has become the current state.
+ *
+ * Implementations should keep this method fast to avoid stalling the locked state mutation.
+ */
+ abstract fun onStateMutated()
+ }
+} \ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index edacf188b333..9a19c2df8791 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -64,9 +64,11 @@ import com.android.server.LocalServices
import com.android.server.PermissionThread
import com.android.server.ServiceThread
import com.android.server.SystemConfig
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal
import com.android.server.permission.access.AccessCheckingService
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AppOpUri
+import com.android.server.permission.access.DevicePermissionUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PermissionUri
@@ -110,6 +112,9 @@ class PermissionService(
private val policy =
service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy
+ private val devicePolicy =
+ service.getSchemePolicy(UidUri.SCHEME, DevicePermissionUri.SCHEME) as DevicePermissionPolicy
+
private val context = service.context
private lateinit var metricsLogger: MetricsLogger
private lateinit var packageManagerInternal: PackageManagerInternal
@@ -130,6 +135,8 @@ class PermissionService(
@GuardedBy("storageVolumeLock")
private val storageVolumePackageNames = ArrayMap<String?, MutableList<String>>()
+ private var virtualDeviceManagerInternal: VirtualDeviceManagerInternal? = null
+
private lateinit var permissionControllerManager: PermissionControllerManager
/**
@@ -152,7 +159,6 @@ class PermissionService(
systemConfig = SystemConfig.getInstance()
userManagerInternal = LocalServices.getService(UserManagerInternal::class.java)
userManagerService = UserManagerService.getInstance()
-
// The package info cache is the cache for package and permission information.
// Disable the package info and package permission caches locally but leave the
// checkPermission cache active.
@@ -460,7 +466,7 @@ class PermissionService(
return size
}
- override fun checkUidPermission(uid: Int, permissionName: String): Int {
+ override fun checkUidPermission(uid: Int, permissionName: String, deviceId: Int): Int {
val userId = UserHandle.getUserId(uid)
if (!userManagerInternal.exists(userId)) {
return PackageManager.PERMISSION_DENIED
@@ -482,7 +488,7 @@ class PermissionService(
return PackageManager.PERMISSION_DENIED
}
val isPermissionGranted = service.getState {
- isPermissionGranted(packageState, userId, permissionName)
+ isPermissionGranted(packageState, userId, permissionName, deviceId)
}
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
@@ -515,7 +521,12 @@ class PermissionService(
return false
}
- override fun checkPermission(packageName: String, permissionName: String, userId: Int): Int {
+ override fun checkPermission(
+ packageName: String,
+ permissionName: String,
+ deviceId: Int,
+ userId: Int
+ ): Int {
if (!userManagerInternal.exists(userId)) {
return PackageManager.PERMISSION_DENIED
}
@@ -524,7 +535,7 @@ class PermissionService(
.use { it.getPackageState(packageName) } ?: return PackageManager.PERMISSION_DENIED
val isPermissionGranted = service.getState {
- isPermissionGranted(packageState, userId, permissionName)
+ isPermissionGranted(packageState, userId, permissionName, deviceId)
}
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
@@ -542,19 +553,21 @@ class PermissionService(
private fun GetStateScope.isPermissionGranted(
packageState: PackageState,
userId: Int,
- permissionName: String
+ permissionName: String,
+ deviceId: Int
): Boolean {
val appId = packageState.appId
// Note that instant apps can't have shared UIDs, so we only need to check the current
// package state.
val isInstantApp = packageState.getUserStateOrDefault(userId).isInstantApp
- if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName)) {
+ if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName, deviceId)) {
return true
}
val fullerPermissionName = FULLER_PERMISSIONS[permissionName]
if (fullerPermissionName != null &&
- isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName)) {
+ isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName, deviceId)
+ ) {
return true
}
@@ -568,9 +581,10 @@ class PermissionService(
appId: Int,
userId: Int,
isInstantApp: Boolean,
- permissionName: String
+ permissionName: String,
+ deviceId: Int,
): Boolean {
- val flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
+ val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
if (!PermissionFlags.isPermissionGranted(flags)) {
return false
}
@@ -601,7 +615,8 @@ class PermissionService(
?: return emptySet()
return permissionFlags.mapNotNullIndexedTo(ArraySet()) { _, permissionName, _ ->
- if (isPermissionGranted(packageState, userId, permissionName)) {
+ if (isPermissionGranted(
+ packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT)) {
permissionName
} else {
null
@@ -640,18 +655,26 @@ class PermissionService(
}
}
- override fun grantRuntimePermission(packageName: String, permissionName: String, userId: Int) {
- setRuntimePermissionGranted(packageName, userId, permissionName, isGranted = true)
+ override fun grantRuntimePermission(
+ packageName: String,
+ permissionName: String,
+ deviceId: Int,
+ userId: Int
+ ) {
+ setRuntimePermissionGranted(
+ packageName, userId, permissionName, deviceId, isGranted = true
+ )
}
override fun revokeRuntimePermission(
packageName: String,
permissionName: String,
+ deviceId: Int,
userId: Int,
reason: String?
) {
setRuntimePermissionGranted(
- packageName, userId, permissionName, isGranted = false, revokeReason = reason
+ packageName, userId, permissionName, deviceId, isGranted = false, revokeReason = reason
)
}
@@ -660,8 +683,8 @@ class PermissionService(
userId: Int
) {
setRuntimePermissionGranted(
- packageName, userId, Manifest.permission.POST_NOTIFICATIONS, isGranted = false,
- skipKillUid = true
+ packageName, userId, Manifest.permission.POST_NOTIFICATIONS, Context.DEVICE_ID_DEFAULT,
+ isGranted = false, skipKillUid = true
)
}
@@ -673,6 +696,7 @@ class PermissionService(
packageName: String,
userId: Int,
permissionName: String,
+ deviceId: Int,
isGranted: Boolean,
skipKillUid: Boolean = false,
revokeReason: String? = null
@@ -748,7 +772,7 @@ class PermissionService(
}
setRuntimePermissionGranted(
- packageState, userId, permissionName, isGranted, canManageRolePermission,
+ packageState, userId, permissionName, deviceId, isGranted, canManageRolePermission,
overridePolicyFixed, reportError = true, methodName
)
}
@@ -782,14 +806,16 @@ class PermissionService(
if (permissionState ==
PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
setRuntimePermissionGranted(
- packageState, userId, permissionName, isGranted = true,
- canManageRolePermission = false, overridePolicyFixed = false,
- reportError = false, "setRequestedPermissionStates"
+ packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT,
+ isGranted = true, canManageRolePermission = false,
+ overridePolicyFixed = false, reportError = false,
+ "setRequestedPermissionStates"
)
updatePermissionFlags(
packageState.appId, userId, permissionName,
+ Context.DEVICE_ID_DEFAULT,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED or
- PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
+ PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
canUpdateSystemFlags = false,
reportErrorForUnknownPermission = false,
isPermissionRequested = true, "setRequestedPermissionStates",
@@ -816,6 +842,7 @@ class PermissionService(
packageState: PackageState,
userId: Int,
permissionName: String,
+ deviceId: Int,
isGranted: Boolean,
canManageRolePermission: Boolean,
overridePolicyFixed: Boolean,
@@ -871,7 +898,7 @@ class PermissionService(
}
val appId = packageState.appId
- val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
+ val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
if (permissionName !in androidPackage.requestedPermissions && oldFlags == 0) {
if (reportError) {
@@ -934,7 +961,7 @@ class PermissionService(
return
}
- with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
+ setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
if (permission.isRuntime) {
val action = if (isGranted) {
@@ -963,7 +990,12 @@ class PermissionService(
with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
}
- override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
+ override fun getPermissionFlags(
+ packageName: String,
+ permissionName: String,
+ deviceId: Int,
+ userId: Int,
+ ): Int {
if (!userManagerInternal.exists(userId)) {
Slog.w(LOG_TAG, "getPermissionFlags: Unknown user $userId")
return 0
@@ -994,7 +1026,8 @@ class PermissionService(
}
val flags =
- with(policy) { getPermissionFlags(packageState.appId, userId, permissionName) }
+ getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
+
return PermissionFlags.toApiFlags(flags)
}
}
@@ -1002,6 +1035,7 @@ class PermissionService(
override fun isPermissionRevokedByPolicy(
packageName: String,
permissionName: String,
+ deviceId: Int,
userId: Int
): Boolean {
if (!userManagerInternal.exists(userId)) {
@@ -1018,13 +1052,13 @@ class PermissionService(
.use { it.getPackageState(packageName) } ?: return false
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName)) {
+ if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
return false
}
- val flags = with(policy) {
- getPermissionFlags(packageState.appId, userId, permissionName)
- }
+ val flags =
+ getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
+
return flags.hasBits(PermissionFlags.POLICY_FIXED)
}
}
@@ -1046,7 +1080,8 @@ class PermissionService(
override fun shouldShowRequestPermissionRationale(
packageName: String,
permissionName: String,
- userId: Int
+ deviceId: Int,
+ userId: Int,
): Boolean {
if (!userManagerInternal.exists(userId)) {
Slog.w(LOG_TAG, "shouldShowRequestPermissionRationale: Unknown user $userId")
@@ -1068,11 +1103,11 @@ class PermissionService(
val flags: Int
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName)) {
+ if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
return false
}
- flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
+ flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
}
if (flags.hasAnyBit(UNREQUESTABLE_MASK)) {
return false
@@ -1104,6 +1139,7 @@ class PermissionService(
flagMask: Int,
flagValues: Int,
enforceAdjustPolicyPermission: Boolean,
+ deviceId: Int,
userId: Int
) {
val callingUid = Binder.getCallingUid()
@@ -1199,7 +1235,7 @@ class PermissionService(
val appId = packageState.appId
service.mutateState {
updatePermissionFlags(
- appId, userId, permissionName, flagMask, flagValues, canUpdateSystemFlags,
+ appId, userId, permissionName, deviceId, flagMask, flagValues, canUpdateSystemFlags,
reportErrorForUnknownPermission = true, isPermissionRequested,
"updatePermissionFlags", packageName
)
@@ -1248,8 +1284,9 @@ class PermissionService(
val androidPackage = packageState.androidPackage ?: return@forEach
androidPackage.requestedPermissions.forEach { permissionName ->
updatePermissionFlags(
- packageState.appId, userId, permissionName, flagMask, flagValues,
- canUpdateSystemFlags, reportErrorForUnknownPermission = false,
+ packageState.appId, userId, permissionName, Context.DEVICE_ID_DEFAULT,
+ flagMask, flagValues, canUpdateSystemFlags,
+ reportErrorForUnknownPermission = false,
isPermissionRequested = true, "updatePermissionFlagsForAllApps", packageName
)
}
@@ -1264,6 +1301,7 @@ class PermissionService(
appId: Int,
userId: Int,
permissionName: String,
+ deviceId: Int,
flagMask: Int,
flagValues: Int,
canUpdateSystemFlags: Boolean,
@@ -1298,7 +1336,7 @@ class PermissionService(
return
}
- val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
+ val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
if (!isPermissionRequested && oldFlags == 0) {
Slog.w(
LOG_TAG, "$methodName: Permission $permissionName isn't requested by package" +
@@ -1308,7 +1346,7 @@ class PermissionService(
}
val newFlags = PermissionFlags.updateFlags(permission, oldFlags, flagMask, flagValues)
- with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
+ setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
}
override fun getAllowlistedRestrictedPermissions(
@@ -1365,6 +1403,63 @@ class PermissionService(
)
}
+ private fun GetStateScope.getPermissionFlagsWithPolicy(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ deviceId: Int,
+ ): Int {
+ return if (deviceId == Context.DEVICE_ID_DEFAULT) {
+ with(policy) { getPermissionFlags(appId, userId, permissionName) }
+ } else {
+ val virtualDeviceManagerInternal = virtualDeviceManagerInternal
+ if (virtualDeviceManagerInternal == null) {
+ Slog.e(LOG_TAG, "Virtual device manager service is not available.")
+ return 0
+ }
+ val persistentDeviceId =
+ virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
+ if (persistentDeviceId != null) {
+ with(devicePolicy) {
+ getPermissionFlags(appId, persistentDeviceId, userId, permissionName)
+ }
+ } else {
+ Slog.e(LOG_TAG, "Invalid device ID $deviceId.")
+ 0
+ }
+ }
+ }
+
+ private fun MutateStateScope.setPermissionFlagsWithPolicy(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ deviceId: Int,
+ flags: Int
+ ): Boolean {
+ return if (deviceId == Context.DEVICE_ID_DEFAULT) {
+ with(policy) {
+ setPermissionFlags(appId, userId, permissionName, flags)
+ }
+ } else {
+ val virtualDeviceManagerInternal = virtualDeviceManagerInternal
+ if (virtualDeviceManagerInternal == null) {
+ Slog.e(LOG_TAG, "Virtual device manager service is not available.")
+ return false
+ }
+ val persistentDeviceId =
+ virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
+ if (persistentDeviceId != null) {
+ with(devicePolicy) {
+ setPermissionFlags(appId, persistentDeviceId, userId, permissionName, flags)
+ }
+ } else {
+ Slog.e(LOG_TAG, "Invalid device ID $deviceId.")
+ false
+ }
+ }
+ }
+
/**
* This method does not enforce checks on the caller, should only be called after
* required checks.
@@ -1539,8 +1634,7 @@ class PermissionService(
) {
service.mutateState {
with(policy) {
- val permissionsFlags =
- getUidPermissionFlags(appId, userId) ?: return@mutateState
+ val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState
val permissions = getPermissions()
androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission ->
@@ -1661,8 +1755,6 @@ class PermissionService(
)
}
-
-
override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
requireNotNull(permissionName) { "permissionName cannot be null" }
val packageNames = ArraySet<String>()
@@ -1879,7 +1971,7 @@ class PermissionService(
println("Permissions:")
withIndent {
userState.appIdPermissionFlags[appId]?.forEachIndexed {
- _, permissionName, flags ->
+ _, permissionName, flags ->
val isGranted = PermissionFlags.isPermissionGranted(flags)
println(
"$permissionName: granted=$isGranted, flags=" +
@@ -1888,6 +1980,20 @@ class PermissionService(
}
}
+ userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
+ _, deviceId, devicePermissionFlags ->
+ println("Permissions (Device $deviceId):")
+ withIndent {
+ devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
+ val isGranted = PermissionFlags.isPermissionGranted(flags)
+ println(
+ "$permissionName: granted=$isGranted, flags=" +
+ PermissionFlags.toString(flags)
+ )
+ }
+ }
+ }
+
println("App ops:")
withIndent {
userState.appIdAppOpModes[appId]?.forEachIndexed {_, appOpName, appOpMode ->
@@ -2003,6 +2109,8 @@ class PermissionService(
override fun onSystemReady() {
service.onSystemReady()
+ virtualDeviceManagerInternal =
+ LocalServices.getService(VirtualDeviceManagerInternal::class.java)
permissionControllerManager = PermissionControllerManager(
context, PermissionThread.getHandler()
)
@@ -2412,7 +2520,7 @@ class PermissionService(
}
private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
- if (checkUidPermission(uid, Manifest.permission.BACKUP) !=
+ if (checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
PackageManager.PERMISSION_GRANTED) {
return false
}
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
index 14b4dc3dc7d0..2db2438b9a21 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
@@ -27,6 +27,7 @@ import android.platform.test.annotations.Presubmit;
import android.util.Log;
import com.android.server.backup.UserBackupManagerService;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.android.server.testing.shadows.ShadowEventLog;
import com.android.server.testing.shadows.ShadowSlog;
@@ -46,10 +47,13 @@ public class KeyValueBackupReporterTest {
@Mock private IBackupManagerMonitor mMonitor;
private KeyValueBackupReporter mReporter;
+ private BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
@Before
public void setUp() {
- mReporter = new KeyValueBackupReporter(mBackupManagerService, mObserver, mMonitor);
+ mBackupManagerMonitorEventSender = new BackupManagerMonitorEventSender(mMonitor);
+ mReporter = new KeyValueBackupReporter(
+ mBackupManagerService, mObserver, mBackupManagerMonitorEventSender);
}
@Test
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index bfbc0f50f67a..7349c14ef62b 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -122,6 +122,7 @@ import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.backup.utils.BackupEligibilityRules;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.android.server.testing.shadows.FrameworkShadowLooper;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBackupDataInput;
@@ -260,7 +261,8 @@ public class KeyValueBackupTaskTest {
mBackupHandler = mBackupManagerService.getBackupHandler();
mShadowBackupLooper = shadowOf(mBackupHandler.getLooper());
ShadowEventLog.setUp();
- mReporter = spy(new KeyValueBackupReporter(mBackupManagerService, mObserver, mMonitor));
+ mReporter = spy(new KeyValueBackupReporter(mBackupManagerService, mObserver,
+ new BackupManagerMonitorEventSender(mMonitor)));
when(mPackageManagerInternal.getApplicationEnabledState(any(), anyInt()))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
diff --git a/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningShellCommandTest.java b/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningShellCommandTest.java
index 2d93120681ec..007c0db1b731 100644
--- a/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningShellCommandTest.java
+++ b/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningShellCommandTest.java
@@ -21,12 +21,14 @@ import static com.google.common.truth.Truth8.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.hardware.security.keymint.DeviceInfo;
import android.hardware.security.keymint.IRemotelyProvisionedComponent;
import android.hardware.security.keymint.MacedPublicKey;
@@ -34,28 +36,35 @@ import android.hardware.security.keymint.ProtectedData;
import android.hardware.security.keymint.RpcHardwareInfo;
import android.os.Binder;
import android.os.FileUtils;
+import android.os.OutcomeReceiver;
+import android.os.Process;
+import android.security.rkp.service.RegistrationProxy;
+import android.security.rkp.service.RemotelyProvisionedKey;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
+import java.util.concurrent.Executor;
@RunWith(AndroidJUnit4.class)
public class RemoteProvisioningShellCommandTest {
- private static class Injector extends RemoteProvisioningShellCommand.Injector {
+ private Context mContext;
- private final Map<String, IRemotelyProvisionedComponent> mIrpcs;
+ private static class Injector extends RemoteProvisioningShellCommand.Injector {
- Injector(Map irpcs) {
- mIrpcs = irpcs;
- }
+ Map<String, IRemotelyProvisionedComponent> mIrpcs;
+ Map<String, RegistrationProxy> mRegistrationProxies;
@Override
String[] getIrpcNames() {
@@ -70,6 +79,12 @@ public class RemoteProvisioningShellCommandTest {
}
return irpc;
}
+
+ @Override
+ RegistrationProxy getRegistrationProxy(
+ Context context, int callerUid, String name, Executor executor) {
+ return mRegistrationProxies.get(name);
+ }
}
private static class CommandResult {
@@ -111,10 +126,17 @@ public class RemoteProvisioningShellCommandTest {
code, FileUtils.readTextFile(out, 0, null), FileUtils.readTextFile(err, 0, null));
}
+ @Before
+ public void setUp() {
+ mContext = ApplicationProvider.getApplicationContext();
+ }
+
@Test
public void list_zeroInstances() throws Exception {
+ Injector injector = new Injector();
+ injector.mIrpcs = Map.of();
RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
- new Injector(Map.of()));
+ mContext, Process.SHELL_UID, injector);
CommandResult res = exec(cmd, new String[] {"list"});
assertThat(res.getErr()).isEmpty();
assertThat(res.getCode()).isEqualTo(0);
@@ -124,8 +146,10 @@ public class RemoteProvisioningShellCommandTest {
@Test
public void list_oneInstances() throws Exception {
+ Injector injector = new Injector();
+ injector.mIrpcs = Map.of("default", mock(IRemotelyProvisionedComponent.class));
RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
- new Injector(Map.of("default", mock(IRemotelyProvisionedComponent.class))));
+ mContext, Process.SHELL_UID, injector);
CommandResult res = exec(cmd, new String[] {"list"});
assertThat(res.getErr()).isEmpty();
assertThat(res.getCode()).isEqualTo(0);
@@ -134,10 +158,12 @@ public class RemoteProvisioningShellCommandTest {
@Test
public void list_twoInstances() throws Exception {
+ Injector injector = new Injector();
+ injector.mIrpcs = Map.of(
+ "default", mock(IRemotelyProvisionedComponent.class),
+ "strongbox", mock(IRemotelyProvisionedComponent.class));
RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
- new Injector(Map.of(
- "default", mock(IRemotelyProvisionedComponent.class),
- "strongbox", mock(IRemotelyProvisionedComponent.class))));
+ mContext, Process.SHELL_UID, injector);
CommandResult res = exec(cmd, new String[] {"list"});
assertThat(res.getErr()).isEmpty();
assertThat(res.getCode()).isEqualTo(0);
@@ -158,8 +184,10 @@ public class RemoteProvisioningShellCommandTest {
}).when(defaultMock).generateCertificateRequest(
anyBoolean(), any(), any(), any(), any(), any());
+ Injector injector = new Injector();
+ injector.mIrpcs = Map.of("default", defaultMock);
RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
- new Injector(Map.of("default", defaultMock)));
+ mContext, Process.SHELL_UID, injector);
CommandResult res = exec(cmd, new String[] {
"csr", "--challenge", "dGVzdHRlc3R0ZXN0dGVzdA==", "default"});
verify(defaultMock).generateCertificateRequest(
@@ -189,8 +217,10 @@ public class RemoteProvisioningShellCommandTest {
}).when(defaultMock).generateCertificateRequest(
anyBoolean(), any(), any(), any(), any(), any());
+ Injector injector = new Injector();
+ injector.mIrpcs = Map.of("default", defaultMock);
RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
- new Injector(Map.of("default", defaultMock)));
+ mContext, Process.SHELL_UID, injector);
CommandResult res = exec(cmd, new String[] {
"csr", "--challenge", "dGVzdHRlc3R0ZXN0dGVzdA==", "default"});
verify(defaultMock).generateCertificateRequest(
@@ -215,8 +245,10 @@ public class RemoteProvisioningShellCommandTest {
when(defaultMock.generateCertificateRequestV2(any(), any()))
.thenReturn(new byte[] {0x68, 0x65, 0x6c, 0x6c, 0x6f});
+ Injector injector = new Injector();
+ injector.mIrpcs = Map.of("default", defaultMock);
RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
- new Injector(Map.of("default", defaultMock)));
+ mContext, Process.SHELL_UID, injector);
CommandResult res = exec(cmd, new String[] {"csr", "default"});
verify(defaultMock).generateCertificateRequestV2(new MacedPublicKey[0], new byte[0]);
assertThat(res.getErr()).isEmpty();
@@ -233,8 +265,10 @@ public class RemoteProvisioningShellCommandTest {
when(defaultMock.generateCertificateRequestV2(any(), any()))
.thenReturn(new byte[] {0x68, 0x69});
+ Injector injector = new Injector();
+ injector.mIrpcs = Map.of("default", defaultMock);
RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
- new Injector(Map.of("default", defaultMock)));
+ mContext, Process.SHELL_UID, injector);
CommandResult res = exec(cmd, new String[] {"csr", "--challenge", "dHJpYWw=", "default"});
verify(defaultMock).generateCertificateRequestV2(
new MacedPublicKey[0], new byte[] {0x74, 0x72, 0x69, 0x61, 0x6c});
@@ -242,4 +276,82 @@ public class RemoteProvisioningShellCommandTest {
assertThat(res.getCode()).isEqualTo(0);
assertThat(res.getOut()).isEqualTo("aGk=\n");
}
+
+ @Test
+ public void certify_sameOrderAsReceived() throws Exception {
+ String cert1 = "MIIBqDCCAU2gAwIBAgIUI3FFU7xZno/2Xf/wZzKKquP0ov0wCgYIKoZIzj0EAwIw\n"
+ + "KTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ0wCwYDVQQKDARUZXN0MB4XDTIz\n"
+ + "MDgyMjE5MzgxMFoXDTMzMDgxOTE5MzgxMFowKTELMAkGA1UEBhMCVVMxCzAJBgNV\n"
+ + "BAgMAkNBMQ0wCwYDVQQKDARUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n"
+ + "czOpG6NKOdDjV/yrKjuy0q0jEJvsVLGgTeY+vyKRBJS59OhyRWG6n3aza21bNg5d\n"
+ + "WE9ruz+bcT0IP4kDbiS0y6NTMFEwHQYDVR0OBBYEFHYfJxCUipNI7qRqvczcWsOb\n"
+ + "FIDPMB8GA1UdIwQYMBaAFHYfJxCUipNI7qRqvczcWsObFIDPMA8GA1UdEwEB/wQF\n"
+ + "MAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAKm/kpJwlnWkjoLCAddBiSnxbT4EfJIK\n"
+ + "H0j58tg5VazHAiEAnS/kRzU9AbstOZyD7el/ws3gLXkbUNey3pLFutBWsSU=\n";
+ String cert2 = "MIIBpjCCAU2gAwIBAgIUdSzfZzeGr+h70JPO7Sxwdkw99iMwCgYIKoZIzj0EAwIw\n"
+ + "KTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ0wCwYDVQQKDARUZXN0MB4XDTIz\n"
+ + "MDgyMjIwMTcyMFoXDTMzMDgxOTIwMTcyMFowKTELMAkGA1UEBhMCVVMxCzAJBgNV\n"
+ + "BAgMAkNBMQ0wCwYDVQQKDARUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n"
+ + "voGJi4DxuqH8rzPV6Eq0OVULc0xFzaM0500VBqiQEB7Qt0Ktk2d+3bUrFAb3SZV4\n"
+ + "6TIdb7SkynvaDtr0x45Ng6NTMFEwHQYDVR0OBBYEFMeGjvGV0ADPBJk5/FPoW9HQ\n"
+ + "uTc6MB8GA1UdIwQYMBaAFMeGjvGV0ADPBJk5/FPoW9HQuTc6MA8GA1UdEwEB/wQF\n"
+ + "MAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgd1gu7iiNOQXaQUn5BT3WwWR0Yk78ndWt\n"
+ + "ew7tRiTOhFcCIFURi6WcNH0oWa6IbwBSMC9aZlo98Fbg+dTwhLAAw+PW\n";
+ byte[] cert1Bytes = Base64.getDecoder().decode(cert1.replaceAll("\\s+", ""));
+ byte[] cert2Bytes = Base64.getDecoder().decode(cert2.replaceAll("\\s+", ""));
+ byte[] certChain = Arrays.copyOf(cert1Bytes, cert1Bytes.length + cert2Bytes.length);
+ System.arraycopy(cert2Bytes, 0, certChain, cert1Bytes.length, cert2Bytes.length);
+ RemotelyProvisionedKey keyMock = mock(RemotelyProvisionedKey.class);
+ when(keyMock.getEncodedCertChain()).thenReturn(certChain);
+ RegistrationProxy defaultMock = mock(RegistrationProxy.class);
+ doAnswer(invocation -> {
+ ((OutcomeReceiver<RemotelyProvisionedKey, Exception>) invocation.getArgument(3))
+ .onResult(keyMock);
+ return null;
+ }).when(defaultMock).getKeyAsync(anyInt(), any(), any(), any());
+
+ Injector injector = new Injector();
+ injector.mRegistrationProxies = Map.of("default", defaultMock);
+ RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
+ mContext, Process.SHELL_UID, injector);
+ CommandResult res = exec(cmd, new String[] {"certify", "default"});
+ assertThat(res.getErr()).isEmpty();
+ assertThat(res.getCode()).isEqualTo(0);
+ assertThat(res.getOut()).isEqualTo(
+ "-----BEGIN CERTIFICATE-----\n" + cert1 + "-----END CERTIFICATE-----\n"
+ + "-----BEGIN CERTIFICATE-----\n" + cert2 + "-----END CERTIFICATE-----\n");
+ }
+
+ @Test
+ public void certify_noBlankLineBeforeTrailer() throws Exception {
+ String cert = "MIIB2zCCAYGgAwIBAgIRAOpN7Em1k7gaqLAB2dzXUTYwCgYIKoZIzj0EAwIwKTET\n"
+ + "MBEGA1UEChMKR29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EzMB4XDTIzMDgx\n"
+ + "ODIzMzI1MloXDTIzMDkyMTIzMzI1MlowOTEMMAoGA1UEChMDVEVFMSkwJwYDVQQD\n"
+ + "EyBlYTRkZWM0OWI1OTNiODFhYThiMDAxZDlkY2Q3NTEzNjBZMBMGByqGSM49AgEG\n"
+ + "CCqGSM49AwEHA0IABHM/cKZblmlw8bdGbDXnX+ZiLiGjSjaLHXYOoHDrVArAMXUi\n"
+ + "L6brhcUPaqSGcVLcfFZbaFMOxXW6TsGdQiwJ0iyjejB4MB0GA1UdDgQWBBTYzft+\n"
+ + "X32TH/Hh+ngwQF6aPhnfXDAfBgNVHSMEGDAWgBQT4JObI9mzNNW2FRsHRcw4zVn2\n"
+ + "8jAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAVBgorBgEEAdZ5AgEe\n"
+ + "BAehARoABAAAMAoGCCqGSM49BAMCA0gAMEUCIDc0OR7CzIYw0myTr0y/Brl1nZyk\n"
+ + "eGSQp615WpTwYhwxAiEApM10gSIKBIo7Z4/FNzkuiz1zZwW9+Dcqisqxkfe6icQ=\n";
+ byte[] certBytes = Base64.getDecoder().decode(cert.replaceAll("\\s+", ""));
+ RemotelyProvisionedKey keyMock = mock(RemotelyProvisionedKey.class);
+ when(keyMock.getEncodedCertChain()).thenReturn(certBytes);
+ RegistrationProxy defaultMock = mock(RegistrationProxy.class);
+ doAnswer(invocation -> {
+ ((OutcomeReceiver<RemotelyProvisionedKey, Exception>) invocation.getArgument(3))
+ .onResult(keyMock);
+ return null;
+ }).when(defaultMock).getKeyAsync(anyInt(), any(), any(), any());
+
+ Injector injector = new Injector();
+ injector.mRegistrationProxies = Map.of("strongbox", defaultMock);
+ RemoteProvisioningShellCommand cmd = new RemoteProvisioningShellCommand(
+ mContext, Process.SHELL_UID, injector);
+ CommandResult res = exec(cmd, new String[] {"certify", "strongbox"});
+ assertThat(res.getErr()).isEmpty();
+ assertThat(res.getCode()).isEqualTo(0);
+ assertThat(res.getOut()).isEqualTo(
+ "-----BEGIN CERTIFICATE-----\n" + cert + "-----END CERTIFICATE-----\n");
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
index de27d773504e..e672928c5403 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
@@ -102,7 +102,7 @@ public class SettingsToPropertiesMapperTest {
).when(() -> Settings.Global.getString(any(), anyString()));
mTestMapper = new SettingsToPropertiesMapper(
- mMockContentResolver, TEST_MAPPING, new String[] {});
+ mMockContentResolver, TEST_MAPPING, new String[] {}, new String[] {});
}
@After
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 7eb78eb3480d..65286d9aabc7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -62,7 +62,7 @@ import com.android.server.backup.params.BackupParams;
import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.utils.BackupEligibilityRules;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupManagerMonitorEventSender;
import com.google.common.collect.ImmutableSet;
@@ -98,6 +98,7 @@ public class UserBackupManagerServiceTest {
@Mock LifecycleOperationStorage mOperationStorage;
@Mock JobScheduler mJobScheduler;
@Mock BackupHandler mBackupHandler;
+ @Mock BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
private TestableContext mContext;
private MockitoSession mSession;
@@ -107,7 +108,7 @@ public class UserBackupManagerServiceTest {
public void setUp() throws Exception {
mSession = mockitoSession()
.initMocks(this)
- .mockStatic(BackupManagerMonitorUtils.class)
+ .mockStatic(BackupManagerMonitorEventSender.class)
.mockStatic(FeatureFlagUtils.class)
// TODO(b/263239775): Remove unnecessary stubbing.
.strictness(Strictness.LENIENT)
@@ -124,7 +125,7 @@ public class UserBackupManagerServiceTest {
mService.setEnabled(true);
mService.setSetupComplete(true);
mService.enqueueFullBackup("com.test.backup.app", /* lastBackedUp= */ 0);
- }
+ }
@After
public void tearDown() {
@@ -297,9 +298,9 @@ public class UserBackupManagerServiceTest {
new DataTypeResult(/* dataType */ "type_2"));
mService.reportDelayedRestoreResult(TEST_PACKAGE, results);
- verify(() -> BackupManagerMonitorUtils.sendAgentLoggingResults(
- eq(mBackupManagerMonitor), eq(packageInfo), eq(results), eq(
- BackupAnnotations.OperationType.RESTORE)));
+
+ verify(mBackupManagerMonitorEventSender).sendAgentLoggingResults(
+ eq(packageInfo), eq(results), eq(BackupAnnotations.OperationType.RESTORE));
}
private static PackageInfo getPackageInfo(String packageName) {
@@ -309,7 +310,7 @@ public class UserBackupManagerServiceTest {
return packageInfo;
}
- private static class TestBackupService extends UserBackupManagerService {
+ private class TestBackupService extends UserBackupManagerService {
boolean isEnabledStatePersisted = false;
boolean shouldUseNewBackupEligibilityRules = false;
@@ -356,6 +357,11 @@ public class UserBackupManagerServiceTest {
return mWorkerThread;
}
+ @Override
+ BackupManagerMonitorEventSender getBMMEventSender(IBackupManagerMonitor monitor) {
+ return mBackupManagerMonitorEventSender;
+ }
+
private void waitForAsyncOperation() {
if (mWorkerThread == null) {
return;
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java
new file mode 100644
index 000000000000..8e17b3a58769
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.utils;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.backup.BackupManagerMonitor;
+import android.os.Bundle;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+
+public class BackupManagerMonitorDumpsysUtilsTest {
+ private File mTempFile;
+ private TestBackupManagerMonitorDumpsysUtils mBackupManagerMonitorDumpsysUtils;
+ @Rule
+ public TemporaryFolder tmp = new TemporaryFolder();
+
+ @Before
+ public void setUp() throws Exception {
+ mTempFile = tmp.newFile("testbmmevents.txt");
+ mBackupManagerMonitorDumpsysUtils = new TestBackupManagerMonitorDumpsysUtils();
+ }
+
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_bundleIsNull_noLogsWrittenToFile()
+ throws Exception {
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(null);
+
+ assertTrue(mTempFile.length() == 0);
+
+ }
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_missingID_noLogsWrittenToFile()
+ throws Exception {
+ Bundle event = new Bundle();
+ event.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, 1);
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+
+ assertTrue(mTempFile.length() == 0);
+ }
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_missingCategory_noLogsWrittenToFile()
+ throws Exception {
+ Bundle event = new Bundle();
+ event.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, 1);
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+
+ assertTrue(mTempFile.length() == 0);
+ }
+
+ private class TestBackupManagerMonitorDumpsysUtils
+ extends BackupManagerMonitorDumpsysUtils {
+ TestBackupManagerMonitorDumpsysUtils() {
+ super();
+ }
+
+ @Override
+ public File getBMMEventsFile() {
+ return mTempFile;
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java
index 093ad3cc7bb3..3af2932ee937 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java
@@ -30,11 +30,11 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.IBackupAgent;
-import android.app.backup.BackupAnnotations;
import android.app.backup.BackupAnnotations.OperationType;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupRestoreEventLogger;
@@ -62,39 +62,65 @@ import java.util.List;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class BackupManagerMonitorUtilsTest {
+public class BackupManagerMonitorEventSenderTest {
@Mock private IBackupManagerMonitor mMonitorMock;
+ @Mock private BackupManagerMonitorDumpsysUtils mBackupManagerMonitorDumpsysUtilsMock;
+
+ private BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mBackupManagerMonitorEventSender = new BackupManagerMonitorEventSender(mMonitorMock,
+ mBackupManagerMonitorDumpsysUtilsMock);
+ }
+
+ @Test
+ public void monitorEvent_monitorIsNull_sendBundleToDumpsys() throws Exception {
+ Bundle extras = new Bundle();
+ extras.putInt(EXTRA_LOG_OPERATION_TYPE, OperationType.RESTORE);
+ mBackupManagerMonitorEventSender.setMonitor(null);
+ mBackupManagerMonitorEventSender.monitorEvent(0, null, 0, extras);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
+
+ verify(mBackupManagerMonitorDumpsysUtilsMock).parseBackupManagerMonitorRestoreEventForDumpsys(any(
+ Bundle.class));
}
@Test
- public void monitorEvent_monitorIsNull_returnsNull() throws Exception {
- IBackupManagerMonitor result = BackupManagerMonitorUtils.monitorEvent(null, 0, null, 0,
- null);
+ public void monitorEvent_monitorIsNull_doNotCallOnEvent() throws Exception {
+ mBackupManagerMonitorEventSender = new BackupManagerMonitorEventSender(null);
+ mBackupManagerMonitorEventSender.monitorEvent(0, null, 0, null);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
- assertThat(result).isNull();
+ verify(mMonitorMock, never()).onEvent(any(Bundle.class));
}
@Test
- public void monitorEvent_monitorOnEventThrows_returnsNull() throws Exception {
+ public void monitorEvent_monitorOnEventThrows_setsMonitorToNull() throws Exception {
doThrow(new RemoteException()).when(mMonitorMock).onEvent(any(Bundle.class));
- IBackupManagerMonitor result = BackupManagerMonitorUtils.monitorEvent(mMonitorMock, 0, null,
- 0, null);
+ mBackupManagerMonitorEventSender.monitorEvent(0, null, 0, null);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
verify(mMonitorMock).onEvent(any(Bundle.class));
- assertThat(result).isNull();
+ assertThat(monitor).isNull();
+ }
+
+ @Test
+ public void monitorEvent_extrasAreNull_doNotSendBundleToDumpsys() throws Exception {
+ mBackupManagerMonitorEventSender.monitorEvent(1, null, 2, null);
+
+ verify(mBackupManagerMonitorDumpsysUtilsMock, never())
+ .parseBackupManagerMonitorRestoreEventForDumpsys(any(Bundle.class));
}
@Test
public void monitorEvent_packageAndExtrasAreNull_fillsBundleCorrectly() throws Exception {
- IBackupManagerMonitor result = BackupManagerMonitorUtils.monitorEvent(mMonitorMock, 1, null,
- 2, null);
+ mBackupManagerMonitorEventSender.monitorEvent(1, null, 2, null);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
- assertThat(result).isEqualTo(mMonitorMock);
+ assertThat(monitor).isEqualTo(mMonitorMock);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mMonitorMock).onEvent(bundleCaptor.capture());
Bundle eventBundle = bundleCaptor.getValue();
@@ -112,10 +138,10 @@ public class BackupManagerMonitorUtilsTest {
extras.putInt("key1", 4);
extras.putString("key2", "value2");
- IBackupManagerMonitor result = BackupManagerMonitorUtils.monitorEvent(mMonitorMock, 1,
- packageInfo, 2, extras);
+ mBackupManagerMonitorEventSender.monitorEvent(1, packageInfo, 2, extras);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
- assertThat(result).isEqualTo(mMonitorMock);
+ assertThat(monitor).isEqualTo(mMonitorMock);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mMonitorMock).onEvent(bundleCaptor.capture());
Bundle eventBundle = bundleCaptor.getValue();
@@ -130,7 +156,8 @@ public class BackupManagerMonitorUtilsTest {
}
@Test
- public void monitorEvent_packageAndExtrasAreNotNull_fillsBundleCorrectlyLong() throws Exception {
+ public void monitorEvent_packageAndExtrasAreNotNull_fillsBundleCorrectlyLong()
+ throws Exception {
PackageInfo packageInfo = new PackageInfo();
packageInfo.packageName = "test.package";
packageInfo.versionCode = 3;
@@ -139,10 +166,10 @@ public class BackupManagerMonitorUtilsTest {
extras.putInt("key1", 4);
extras.putString("key2", "value2");
- IBackupManagerMonitor result = BackupManagerMonitorUtils.monitorEvent(mMonitorMock, 1,
- packageInfo, 2, extras);
+ mBackupManagerMonitorEventSender.monitorEvent(1, packageInfo, 2, extras);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
- assertThat(result).isEqualTo(mMonitorMock);
+ assertThat(monitor).isEqualTo(mMonitorMock);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mMonitorMock).onEvent(bundleCaptor.capture());
Bundle eventBundle = bundleCaptor.getValue();
@@ -158,15 +185,45 @@ public class BackupManagerMonitorUtilsTest {
}
@Test
+ public void monitorEvent_eventOpTypeIsRestore_sendBundleToDumpsys() throws Exception {
+ Bundle extras = new Bundle();
+ extras.putInt(EXTRA_LOG_OPERATION_TYPE, OperationType.RESTORE);
+ mBackupManagerMonitorEventSender.monitorEvent(1, null, 2, extras);
+
+ verify(mBackupManagerMonitorDumpsysUtilsMock).parseBackupManagerMonitorRestoreEventForDumpsys(any(
+ Bundle.class));
+ }
+
+ @Test
+ public void monitorEvent_eventOpTypeIsBackup_doNotSendBundleToDumpsys() throws Exception {
+ Bundle extras = new Bundle();
+ extras.putInt(EXTRA_LOG_OPERATION_TYPE, OperationType.BACKUP);
+ mBackupManagerMonitorEventSender.monitorEvent(1, null, 2, extras);
+
+ verify(mBackupManagerMonitorDumpsysUtilsMock, never())
+ .parseBackupManagerMonitorRestoreEventForDumpsys(any(Bundle.class));
+ }
+
+ @Test
+ public void monitorEvent_eventOpTypeIsUnknown_doNotSendBundleToDumpsys() throws Exception {
+ Bundle extras = new Bundle();
+ extras.putInt(EXTRA_LOG_OPERATION_TYPE, OperationType.UNKNOWN);
+ mBackupManagerMonitorEventSender.monitorEvent(1, null, 2, extras);
+
+ verify(mBackupManagerMonitorDumpsysUtilsMock, never())
+ .parseBackupManagerMonitorRestoreEventForDumpsys(any(Bundle.class));
+ }
+
+ @Test
public void monitorAgentLoggingResults_onBackup_fillsBundleCorrectly() throws Exception {
PackageInfo packageInfo = new PackageInfo();
packageInfo.packageName = "test.package";
// Mock an agent that returns a logging result.
IBackupAgent agent = setUpLoggingAgentForOperation(OperationType.BACKUP);
- IBackupManagerMonitor monitor =
- BackupManagerMonitorUtils.monitorAgentLoggingResults(
- mMonitorMock, packageInfo, agent);
+
+ mBackupManagerMonitorEventSender.monitorAgentLoggingResults(packageInfo, agent);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
assertCorrectBundleSentToMonitor(monitor, OperationType.BACKUP);
}
@@ -178,9 +235,8 @@ public class BackupManagerMonitorUtilsTest {
// Mock an agent that returns a logging result.
IBackupAgent agent = setUpLoggingAgentForOperation(OperationType.RESTORE);
- IBackupManagerMonitor monitor =
- BackupManagerMonitorUtils.monitorAgentLoggingResults(
- mMonitorMock, packageInfo, agent);
+ mBackupManagerMonitorEventSender.monitorAgentLoggingResults(packageInfo, agent);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
assertCorrectBundleSentToMonitor(monitor, OperationType.RESTORE);
}
@@ -217,9 +273,9 @@ public class BackupManagerMonitorUtilsTest {
List<BackupRestoreEventLogger.DataTypeResult> loggingResults = new ArrayList<>();
loggingResults.add(new BackupRestoreEventLogger.DataTypeResult("testLoggingResult"));
- IBackupManagerMonitor monitor = BackupManagerMonitorUtils.sendAgentLoggingResults(
- mMonitorMock, packageInfo, loggingResults, OperationType.BACKUP);
-
+ mBackupManagerMonitorEventSender.sendAgentLoggingResults(
+ packageInfo, loggingResults, OperationType.BACKUP);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
assertCorrectBundleSentToMonitor(monitor, OperationType.BACKUP);
}
@@ -230,8 +286,9 @@ public class BackupManagerMonitorUtilsTest {
List<BackupRestoreEventLogger.DataTypeResult> loggingResults = new ArrayList<>();
loggingResults.add(new BackupRestoreEventLogger.DataTypeResult("testLoggingResult"));
- IBackupManagerMonitor monitor = BackupManagerMonitorUtils.sendAgentLoggingResults(
- mMonitorMock, packageInfo, loggingResults, OperationType.RESTORE);
+ mBackupManagerMonitorEventSender.sendAgentLoggingResults(
+ packageInfo, loggingResults, OperationType.RESTORE);
+ IBackupManagerMonitor monitor = mBackupManagerMonitorEventSender.getMonitor();
assertCorrectBundleSentToMonitor(monitor, OperationType.RESTORE);
}
@@ -262,7 +319,7 @@ public class BackupManagerMonitorUtilsTest {
public void putMonitoringExtraString_bundleExists_fillsBundleCorrectly() throws Exception {
Bundle bundle = new Bundle();
- Bundle result = BackupManagerMonitorUtils.putMonitoringExtra(bundle, "key", "value");
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(bundle, "key", "value");
assertThat(result).isEqualTo(bundle);
assertThat(result.size()).isEqualTo(1);
@@ -272,7 +329,7 @@ public class BackupManagerMonitorUtilsTest {
@Test
public void putMonitoringExtraString_bundleDoesNotExist_fillsBundleCorrectly()
throws Exception {
- Bundle result = BackupManagerMonitorUtils.putMonitoringExtra(null, "key", "value");
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(null, "key", "value");
assertThat(result).isNotNull();
assertThat(result.size()).isEqualTo(1);
@@ -284,7 +341,7 @@ public class BackupManagerMonitorUtilsTest {
public void putMonitoringExtraLong_bundleExists_fillsBundleCorrectly() throws Exception {
Bundle bundle = new Bundle();
- Bundle result = BackupManagerMonitorUtils.putMonitoringExtra(bundle, "key", 123);
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(bundle, "key", 123);
assertThat(result).isEqualTo(bundle);
assertThat(result.size()).isEqualTo(1);
@@ -293,7 +350,7 @@ public class BackupManagerMonitorUtilsTest {
@Test
public void putMonitoringExtraLong_bundleDoesNotExist_fillsBundleCorrectly() throws Exception {
- Bundle result = BackupManagerMonitorUtils.putMonitoringExtra(null, "key", 123);
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(null, "key", 123);
assertThat(result).isNotNull();
assertThat(result.size()).isEqualTo(1);
@@ -304,7 +361,7 @@ public class BackupManagerMonitorUtilsTest {
public void putMonitoringExtraBoolean_bundleExists_fillsBundleCorrectly() throws Exception {
Bundle bundle = new Bundle();
- Bundle result = BackupManagerMonitorUtils.putMonitoringExtra(bundle, "key", true);
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(bundle, "key", true);
assertThat(result).isEqualTo(bundle);
assertThat(result.size()).isEqualTo(1);
@@ -314,10 +371,10 @@ public class BackupManagerMonitorUtilsTest {
@Test
public void putMonitoringExtraBoolean_bundleDoesNotExist_fillsBundleCorrectly()
throws Exception {
- Bundle result = BackupManagerMonitorUtils.putMonitoringExtra(null, "key", true);
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(null, "key", true);
assertThat(result).isNotNull();
assertThat(result.size()).isEqualTo(1);
assertThat(result.getBoolean("key")).isTrue();
}
-} \ No newline at end of file
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
index 35d4ffdd94d0..a14073006c31 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -145,7 +145,7 @@ public class RollbackPackageHealthObserverTest {
observer.onHealthCheckFailed(null,
PackageWatchdog.FAILURE_REASON_NATIVE_CRASH, 1));
// non-native crash for the package
- assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_60,
+ assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
observer.onHealthCheckFailed(testFailedPackage,
PackageWatchdog.FAILURE_REASON_APP_CRASH, 1));
// non-native crash for a different package
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 05acd9b8eeb1..8ab45070a017 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -23,6 +23,8 @@ android_test {
"androidx.test.uiautomator_uiautomator",
"mockito-target-minus-junit4",
"servicestests-utils",
+ "platform-test-annotations",
+ "flag-junit",
],
libs: [
diff --git a/services/tests/powerstatstests/AndroidManifest.xml b/services/tests/powerstatstests/AndroidManifest.xml
index d3a88d2bc38c..d6898a1f6589 100644
--- a/services/tests/powerstatstests/AndroidManifest.xml
+++ b/services/tests/powerstatstests/AndroidManifest.xml
@@ -21,6 +21,7 @@
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<queries>
<package android:name="com.android.coretests.apps.bstatstestapp" />
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
index 4fde73bd8408..77124d0120f7 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
@@ -32,6 +32,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Future;
@@ -49,6 +51,7 @@ public class BatteryStatsHistoryIteratorTest {
@Before
public void setup() {
final File historyDir = createTemporaryDirectory(getClass().getSimpleName());
+ mMockClock.currentTime = 3000;
mBatteryStats = new MockBatteryStatsImpl(mMockClock, historyDir);
mBatteryStats.setDummyExternalStatsSync(mExternalStatsSync);
mBatteryStats.setRecordAllHistoryLocked(true);
@@ -70,20 +73,10 @@ public class BatteryStatsHistoryIteratorTest {
}
@Test
- public void testIterator() {
- mMockClock.realtime = 1000;
- mMockClock.uptime = 1000;
+ public void unconstrainedIteration() {
+ prepareHistory();
- mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
- 100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
- 1_000_000, 1_000_000);
- mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
- 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000,
- 2_000_000, 2_000_000);
- mBatteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
- mBatteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
-
- final BatteryStatsHistoryIterator iterator = mBatteryStats.iterateBatteryStatsHistory();
+ final BatteryStatsHistoryIterator iterator = mBatteryStats.iterateBatteryStatsHistory(0, 0);
BatteryStats.HistoryItem item;
@@ -116,23 +109,75 @@ public class BatteryStatsHistoryIteratorTest {
assertThat(iterator.next()).isNull();
}
- // Test history that spans multiple buffers and uses more than 32k different strings.
@Test
- public void tagsLongHistory() {
+ public void constrainedIteration() {
+ prepareHistory();
+
+ // Initial time is 3000
+ assertIncludedEvents(mBatteryStats.iterateBatteryStatsHistory(0, 0),
+ 3_000L, 3_000L, 1003_000L, 2003_000L, 2004_000L);
+ assertIncludedEvents(mBatteryStats.iterateBatteryStatsHistory(1000_000, 0),
+ 1003_000L, 2003_000L, 2004_000L);
+ assertIncludedEvents(mBatteryStats.iterateBatteryStatsHistory(0, 2000_000L),
+ 3_000L, 3_000L, 1003_000L);
+ assertIncludedEvents(mBatteryStats.iterateBatteryStatsHistory(1003_000L, 2004_000L),
+ 1003_000L, 2003_000L);
+ }
+
+ private void prepareHistory() {
+ mMockClock.realtime = 1000;
+ mMockClock.uptime = 1000;
+ mMockClock.currentTime = 3000;
+
mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
1_000_000, 1_000_000);
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000,
+ 2_000_000, 2_000_000);
+ mBatteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
+ mBatteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
+ }
+
+ private void assertIncludedEvents(BatteryStatsHistoryIterator iterator,
+ Long... expectedTimestamps) {
+ ArrayList<Long> actualTimestamps = new ArrayList<>();
+ while (iterator.hasNext()) {
+ BatteryStats.HistoryItem item = iterator.next();
+ actualTimestamps.add(item.currentTime);
+ }
+ assertThat(actualTimestamps).isEqualTo(Arrays.asList(expectedTimestamps));
+ }
+
+ // Test history that spans multiple buffers and uses more than 32k different strings.
+ @Test
+ public void tagsLongHistory() {
+ mMockClock.currentTime = 1_000_000;
+ mMockClock.realtime = 1_000_000;
+ mMockClock.uptime = 1_000_000;
+
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, mMockClock.realtime,
+ mMockClock.uptime, mMockClock.currentTime);
// More than 32k strings
final int eventCount = 0x7FFF + 100;
for (int i = 0; i < eventCount; i++) {
// Names repeat in order to verify de-duping of identical history tags.
String name = "a" + (i % 10);
- mBatteryStats.noteAlarmStartLocked(name, null, APP_UID, 3_000_000, 2_000_000);
- mBatteryStats.noteAlarmFinishLocked(name, null, APP_UID, 3_500_000, 2_500_000);
+ mMockClock.currentTime += 1_000_000;
+ mMockClock.realtime += 1_000_000;
+ mMockClock.uptime += 1_000_000;
+ mBatteryStats.noteAlarmStartLocked(name, null, APP_UID,
+ mMockClock.realtime, mMockClock.uptime);
+ mMockClock.currentTime += 500_000;
+ mMockClock.realtime += 500_000;
+ mMockClock.uptime += 500_000;
+ mBatteryStats.noteAlarmFinishLocked(name, null, APP_UID,
+ mMockClock.realtime, mMockClock.uptime);
}
- final BatteryStatsHistoryIterator iterator = mBatteryStats.iterateBatteryStatsHistory();
+ final BatteryStatsHistoryIterator iterator = mBatteryStats.iterateBatteryStatsHistory(0, 0);
BatteryStats.HistoryItem item;
assertThat(item = iterator.next()).isNotNull();
@@ -146,12 +191,6 @@ public class BatteryStatsHistoryIteratorTest {
assertThat(item.eventTag).isNull();
assertThat(item.time).isEqualTo(1_000_000);
- assertThat(item = iterator.next()).isNotNull();
- assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_UPDATE);
- assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_NONE);
- assertThat(item.eventTag).isNull();
- assertThat(item.time).isEqualTo(2_000_000);
-
for (int i = 0; i < eventCount; i++) {
String name = "a" + (i % 10);
do {
@@ -205,7 +244,7 @@ public class BatteryStatsHistoryIteratorTest {
mExternalStatsSync.updateCpuStats(300, 7_100_000, 4_100_000);
- final BatteryStatsHistoryIterator iterator = mBatteryStats.iterateBatteryStatsHistory();
+ final BatteryStatsHistoryIterator iterator = mBatteryStats.iterateBatteryStatsHistory(0, 0);
BatteryStats.HistoryItem item;
assertThat(item = iterator.next()).isNotNull();
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index f2cbef69c8e5..f22296a6261c 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -24,13 +24,16 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
-import android.os.BatteryStats.CpuUsageDetails;
-import android.os.BatteryStats.EnergyConsumerDetails;
import android.os.BatteryStats.HistoryItem;
import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
import android.telephony.NetworkRegistrationInfo;
+import android.util.AtomicFile;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -38,6 +41,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.BatteryStatsHistory;
import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.internal.os.PowerStats;
import org.junit.Before;
import org.junit.Test;
@@ -71,6 +75,7 @@ public class BatteryStatsHistoryTest {
private BatteryStatsHistory.TraceDelegate mTracer;
@Mock
private BatteryStatsHistory.HistoryStepDetailsCalculator mStepDetailsCalculator;
+ private List<String> mReadFiles = new ArrayList<>();
@Before
public void setUp() {
@@ -85,8 +90,17 @@ public class BatteryStatsHistoryTest {
}
}
mHistoryDir.delete();
+
+ mClock.realtime = 123;
+
mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
- mStepDetailsCalculator, mClock, mTracer);
+ mStepDetailsCalculator, mClock, mTracer) {
+ @Override
+ public boolean readFileToParcel(Parcel out, AtomicFile file) {
+ mReadFiles.add(file.getBaseFile().getName());
+ return super.readFileToParcel(out, file);
+ }
+ };
when(mStepDetailsCalculator.getHistoryStepDetails())
.thenReturn(new BatteryStats.HistoryStepDetails());
@@ -179,70 +193,165 @@ public class BatteryStatsHistoryTest {
@Test
public void testConstruct() {
createActiveFile(mHistory);
- verifyFileNumbers(mHistory, Arrays.asList(0));
- verifyActiveFile(mHistory, "0.bin");
+ verifyFileNames(mHistory, Arrays.asList("123.bh"));
+ verifyActiveFile(mHistory, "123.bh");
}
@Test
public void testStartNextFile() {
- List<Integer> fileList = new ArrayList<>();
- fileList.add(0);
+ mClock.realtime = 123;
+
+ List<String> fileList = new ArrayList<>();
+ fileList.add("123.bh");
createActiveFile(mHistory);
// create file 1 to 31.
for (int i = 1; i < 32; i++) {
- fileList.add(i);
+ mClock.realtime = 1000 * i;
+ fileList.add(mClock.realtime + ".bh");
+
mHistory.startNextFile();
createActiveFile(mHistory);
- verifyFileNumbers(mHistory, fileList);
- verifyActiveFile(mHistory, i + ".bin");
+ verifyFileNames(mHistory, fileList);
+ verifyActiveFile(mHistory, mClock.realtime + ".bh");
}
// create file 32
+ mClock.realtime = 1000 * 32;
mHistory.startNextFile();
createActiveFile(mHistory);
- fileList.add(32);
+ fileList.add("32000.bh");
fileList.remove(0);
// verify file 0 is deleted.
- verifyFileDeleted("0.bin");
- verifyFileNumbers(mHistory, fileList);
- verifyActiveFile(mHistory, "32.bin");
+ verifyFileDeleted("123.bh");
+ verifyFileNames(mHistory, fileList);
+ verifyActiveFile(mHistory, "32000.bh");
// create file 33
+ mClock.realtime = 1000 * 33;
mHistory.startNextFile();
createActiveFile(mHistory);
// verify file 1 is deleted
- fileList.add(33);
+ fileList.add("33000.bh");
fileList.remove(0);
- verifyFileDeleted("1.bin");
- verifyFileNumbers(mHistory, fileList);
- verifyActiveFile(mHistory, "33.bin");
-
- assertEquals(0, mHistory.getHistoryUsedSize());
+ verifyFileDeleted("1000.bh");
+ verifyFileNames(mHistory, fileList);
+ verifyActiveFile(mHistory, "33000.bh");
// create a new BatteryStatsHistory object, it will pick up existing history files.
BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
null, mClock, mTracer);
// verify constructor can pick up all files from file system.
- verifyFileNumbers(history2, fileList);
- verifyActiveFile(history2, "33.bin");
+ verifyFileNames(history2, fileList);
+ verifyActiveFile(history2, "33000.bh");
+
+ mClock.realtime = 1234567;
history2.reset();
createActiveFile(history2);
+
// verify all existing files are deleted.
- for (int i = 2; i < 33; ++i) {
- verifyFileDeleted(i + ".bin");
+ for (String file : fileList) {
+ verifyFileDeleted(file);
}
// verify file 0 is created
- verifyFileNumbers(history2, Arrays.asList(0));
- verifyActiveFile(history2, "0.bin");
+ verifyFileNames(history2, Arrays.asList("1234567.bh"));
+ verifyActiveFile(history2, "1234567.bh");
// create file 1.
+ mClock.realtime = 2345678;
+
history2.startNextFile();
createActiveFile(history2);
- verifyFileNumbers(history2, Arrays.asList(0, 1));
- verifyActiveFile(history2, "1.bin");
+ verifyFileNames(history2, Arrays.asList("1234567.bh", "2345678.bh"));
+ verifyActiveFile(history2, "2345678.bh");
+ }
+
+ @Test
+ public void unconstrainedIteration() {
+ prepareMultiFileHistory();
+
+ mReadFiles.clear();
+
+ // Prepare history for iteration
+ mHistory.iterate(0, 0);
+
+ Parcel parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
+ assertThat(parcel).isNotNull();
+ assertThat(mReadFiles).containsExactly("123.bh");
+
+ // Skip to the end to force reading the next parcel
+ parcel.setDataPosition(parcel.dataSize());
+ mReadFiles.clear();
+ parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
+ assertThat(parcel).isNotNull();
+ assertThat(mReadFiles).containsExactly("1000.bh");
+
+ parcel.setDataPosition(parcel.dataSize());
+ mReadFiles.clear();
+ parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
+ assertThat(parcel).isNotNull();
+ assertThat(mReadFiles).containsExactly("2000.bh");
+
+ parcel.setDataPosition(parcel.dataSize());
+ mReadFiles.clear();
+ parcel = mHistory.getNextParcel(0, Long.MAX_VALUE);
+ assertThat(parcel).isNull();
+ assertThat(mReadFiles).isEmpty();
+ }
+
+ @Test
+ public void constrainedIteration() {
+ prepareMultiFileHistory();
+
+ mReadFiles.clear();
+
+ // Prepare history for iteration
+ mHistory.iterate(1000, 3000);
+
+ Parcel parcel = mHistory.getNextParcel(1000, 3000);
+ assertThat(parcel).isNotNull();
+ assertThat(mReadFiles).containsExactly("1000.bh");
+
+ // Skip to the end to force reading the next parcel
+ parcel.setDataPosition(parcel.dataSize());
+ mReadFiles.clear();
+ parcel = mHistory.getNextParcel(1000, 3000);
+ assertThat(parcel).isNotNull();
+ assertThat(mReadFiles).containsExactly("2000.bh");
+
+ parcel.setDataPosition(parcel.dataSize());
+ mReadFiles.clear();
+ parcel = mHistory.getNextParcel(1000, 3000);
+ assertThat(parcel).isNull();
+ assertThat(mReadFiles).isEmpty();
+ }
+
+ private void prepareMultiFileHistory() {
+ mHistory.forceRecordAllHistory();
+
+ mClock.realtime = 1000;
+ mClock.uptime = 1000;
+ mHistory.recordEvent(mClock.realtime, mClock.uptime,
+ BatteryStats.HistoryItem.EVENT_JOB_START, "job", 42);
+
+ mHistory.startNextFile(); // 1000.bh
+
+ mClock.realtime = 2000;
+ mClock.uptime = 2000;
+ mHistory.recordEvent(mClock.realtime, mClock.uptime,
+ BatteryStats.HistoryItem.EVENT_JOB_FINISH, "job", 42);
+
+ mHistory.startNextFile(); // 2000.bh
+
+ mClock.realtime = 3000;
+ mClock.uptime = 3000;
+ mHistory.recordEvent(mClock.realtime, mClock.uptime,
+ HistoryItem.EVENT_ALARM, "alarm", 42);
+
+ // Flush accumulated history to disk
+ mHistory.startNextFile();
}
private void verifyActiveFile(BatteryStatsHistory history, String file) {
@@ -251,12 +360,11 @@ public class BatteryStatsHistoryTest {
assertTrue(expectedFile.exists());
}
- private void verifyFileNumbers(BatteryStatsHistory history, List<Integer> fileList) {
- assertEquals(fileList.size(), history.getFilesNumbers().size());
+ private void verifyFileNames(BatteryStatsHistory history, List<String> fileList) {
+ assertEquals(fileList.size(), history.getFilesNames().size());
for (int i = 0; i < fileList.size(); i++) {
- assertEquals(fileList.get(i), history.getFilesNumbers().get(i));
- final File expectedFile =
- new File(mHistoryDir, fileList.get(i) + ".bin");
+ assertEquals(fileList.get(i), history.getFilesNames().get(i));
+ final File expectedFile = new File(mHistoryDir, fileList.get(i));
assertTrue(expectedFile.exists());
}
}
@@ -267,6 +375,9 @@ public class BatteryStatsHistoryTest {
private void createActiveFile(BatteryStatsHistory history) {
final File file = history.getActiveFile().getBaseFile();
+ if (file.exists()) {
+ return;
+ }
try {
file.createNewFile();
} catch (IOException e) {
@@ -275,49 +386,18 @@ public class BatteryStatsHistoryTest {
}
@Test
- public void testRecordMeasuredEnergyDetails() {
- mHistory.forceRecordAllHistory();
- mHistory.startRecordingHistory(0, 0, /* reset */ true);
- mHistory.setBatteryState(true /* charging */, BatteryManager.BATTERY_STATUS_CHARGING, 80,
- 1234);
-
- EnergyConsumerDetails details = new EnergyConsumerDetails();
- EnergyConsumerDetails.EnergyConsumer consumer1 =
- new EnergyConsumerDetails.EnergyConsumer();
- consumer1.type = 42;
- consumer1.ordinal = 0;
- consumer1.name = "A";
-
- EnergyConsumerDetails.EnergyConsumer consumer2 =
- new EnergyConsumerDetails.EnergyConsumer();
- consumer2.type = 777;
- consumer2.ordinal = 0;
- consumer2.name = "B/0";
-
- EnergyConsumerDetails.EnergyConsumer consumer3 =
- new EnergyConsumerDetails.EnergyConsumer();
- consumer3.type = 777;
- consumer3.ordinal = 1;
- consumer3.name = "B/1";
-
- EnergyConsumerDetails.EnergyConsumer consumer4 =
- new EnergyConsumerDetails.EnergyConsumer();
- consumer4.type = 314;
- consumer4.ordinal = 1;
- consumer4.name = "C";
-
- details.consumers =
- new EnergyConsumerDetails.EnergyConsumer[]{consumer1, consumer2, consumer3,
- consumer4};
- details.chargeUC = new long[details.consumers.length];
- for (int i = 0; i < details.chargeUC.length; i++) {
- details.chargeUC[i] = 100L * i;
- }
- details.chargeUC[3] = BatteryStats.POWER_DATA_UNAVAILABLE;
-
- mHistory.recordEnergyConsumerDetails(200, 200, details);
-
- BatteryStatsHistoryIterator iterator = mHistory.iterate();
+ public void recordPowerStats() {
+ PowerStats.Descriptor descriptor = new PowerStats.Descriptor(42, "foo", 1, 2,
+ new PersistableBundle());
+ PowerStats powerStats = new PowerStats(descriptor);
+ powerStats.durationMs = 100;
+ powerStats.stats[0] = 200;
+ powerStats.uidStats.put(300, new long[]{400, 500});
+ powerStats.uidStats.put(600, new long[]{700, 800});
+
+ mHistory.recordPowerStats(200, 200, powerStats);
+
+ BatteryStatsHistoryIterator iterator = mHistory.iterate(0, 0);
BatteryStats.HistoryItem item;
assertThat(item = iterator.next()).isNotNull(); // First item contains current time only
@@ -325,62 +405,10 @@ public class BatteryStatsHistoryTest {
String dump = toString(item, /* checkin */ false);
assertThat(dump).contains("+200ms");
- assertThat(dump).contains("ext=energy:A=0 B/0=100 B/1=200");
- assertThat(dump).doesNotContain("C=");
-
- String checkin = toString(item, /* checkin */ true);
- assertThat(checkin).contains("XE");
- assertThat(checkin).contains("A=0,B/0=100,B/1=200");
- assertThat(checkin).doesNotContain("C=");
- }
-
- @Test
- public void cpuUsageDetails() {
- mHistory.forceRecordAllHistory();
- mHistory.startRecordingHistory(0, 0, /* reset */ true);
- mHistory.setBatteryState(true /* charging */, BatteryManager.BATTERY_STATUS_CHARGING, 80,
- 1234);
-
- CpuUsageDetails details = new CpuUsageDetails();
- details.cpuBracketDescriptions = new String[] {"low", "Med", "HIGH"};
- details.uid = 10123;
- details.cpuUsageMs = new long[] { 100, 200, 300};
- mHistory.recordCpuUsage(200, 200, details);
-
- details.uid = 10321;
- details.cpuUsageMs = new long[] { 400, 500, 600};
- mHistory.recordCpuUsage(300, 300, details);
-
- BatteryStatsHistoryIterator iterator = mHistory.iterate();
- BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
- assertThat(item = iterator.next()).isNotNull(); // First item contains current time only
-
- assertThat(item = iterator.next()).isNotNull();
-
- String dump = toString(item, /* checkin */ false);
- assertThat(dump).contains("+200ms");
- assertThat(dump).contains("ext=cpu:u0a123: 100, 200, 300");
- assertThat(dump).contains("ext=cpu-bracket:0:low");
- assertThat(dump).contains("ext=cpu-bracket:1:Med");
- assertThat(dump).contains("ext=cpu-bracket:2:HIGH");
-
- String checkin = toString(item, /* checkin */ true);
- assertThat(checkin).contains("XB,3,0,low");
- assertThat(checkin).contains("XB,3,1,Med");
- assertThat(checkin).contains("XB,3,2,HIGH");
- assertThat(checkin).contains("XC,10123,100,200,300");
-
- assertThat(item = iterator.next()).isNotNull();
-
- dump = toString(item, /* checkin */ false);
- assertThat(dump).contains("+300ms");
- assertThat(dump).contains("ext=cpu:u0a321: 400, 500, 600");
- // Power bracket descriptions are written only once
- assertThat(dump).doesNotContain("ext=cpu-bracket");
-
- checkin = toString(item, /* checkin */ true);
- assertThat(checkin).doesNotContain("XB");
- assertThat(checkin).contains("XC,10321,400,500,600");
+ assertThat(dump).contains("duration=100");
+ assertThat(dump).contains("foo=[200]");
+ assertThat(dump).contains("300: [400, 500]");
+ assertThat(dump).contains("600: [700, 800]");
}
@Test
@@ -399,7 +427,7 @@ public class BatteryStatsHistoryTest {
mHistory.recordNrStateChangeEvent(500, 500,
NetworkRegistrationInfo.NR_STATE_NONE);
- BatteryStatsHistoryIterator iterator = mHistory.iterate();
+ BatteryStatsHistoryIterator iterator = mHistory.iterate(0, 0);
BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
assertThat(item = iterator.next()).isNotNull(); // First item contains current time only
@@ -440,7 +468,7 @@ public class BatteryStatsHistoryTest {
mHistory.recordNrStateChangeEvent(500, 500,
NetworkRegistrationInfo.NR_STATE_NONE);
- BatteryStatsHistoryIterator iterator = mHistory.iterate();
+ BatteryStatsHistoryIterator iterator = mHistory.iterate(0, 0);
BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
assertThat(item = iterator.next()).isNotNull(); // First item contains current time only
@@ -498,7 +526,7 @@ public class BatteryStatsHistoryTest {
mClock.uptime = 1_000_000;
// More than 32k strings
final int tagCount = 0x7FFF + 20;
- for (int tag = 0; tag < tagCount;) {
+ for (int tag = 0; tag < tagCount; ) {
mClock.realtime += 10;
mClock.uptime += 10;
mHistory.recordEvent(mClock.realtime, mClock.uptime, HistoryItem.EVENT_ALARM_START,
@@ -522,8 +550,8 @@ public class BatteryStatsHistoryTest {
int wakelockTagsUnpooled = 0;
int wakeReasonTagsPooled = 0;
int wakeReasonTagsUnpooled = 0;
- for (BatteryStatsHistoryIterator iterator = mHistory.iterate(); iterator.hasNext(); ) {
- HistoryItem item = iterator.next();
+ for (BatteryStatsHistoryIterator iterator = mHistory.iterate(0, 0); iterator.hasNext(); ) {
+ HistoryItem item = iterator.next();
if (item.cmd != HistoryItem.CMD_UPDATE) {
continue;
}
@@ -569,10 +597,40 @@ public class BatteryStatsHistoryTest {
assertThat(wakeReasonTagsUnpooled).isGreaterThan(0);
}
+ @Test
+ public void recordProcStateChange() {
+ mHistory.recordProcessStateChange(200, 200, 42, BatteryConsumer.PROCESS_STATE_BACKGROUND);
+ mHistory.recordProcessStateChange(300, 300, 42, BatteryConsumer.PROCESS_STATE_FOREGROUND);
+ // Large UID, > 0xFFFFFF
+ mHistory.recordProcessStateChange(400, 400,
+ UserHandle.getUid(777, Process.LAST_ISOLATED_UID),
+ BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+
+ BatteryStatsHistoryIterator iterator = mHistory.iterate(0, 0);
+ BatteryStats.HistoryItem item;
+ assertThat(item = iterator.next()).isNotNull(); // First item contains current time only
+
+ assertThat(item = iterator.next()).isNotNull();
+
+ String dump = toString(item, /* checkin */ false);
+ assertThat(dump).contains("+200ms");
+ assertThat(dump).contains("procstate: 42: bg");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ false);
+ assertThat(dump).contains("+300ms");
+ assertThat(dump).contains("procstate: 42: fg");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ false);
+ assertThat(dump).contains("+400ms");
+ assertThat(dump).contains("procstate: u777i999: fgs");
+ }
+
private String toString(BatteryStats.HistoryItem item, boolean checkin) {
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
- mHistoryPrinter.printNextItem(pw, item, 0, checkin, /* verbose */ false);
+ mHistoryPrinter.printNextItem(pw, item, 0, checkin, /* verbose */ true);
pw.flush();
return writer.toString();
}
@@ -596,6 +654,7 @@ public class BatteryStatsHistoryTest {
0xffffffffffffffffL};
// Parcel subarrays of different lengths and assert the size of the resulting parcel
+ testVarintParceler(Arrays.copyOfRange(values, 0, 0), 0);
testVarintParceler(Arrays.copyOfRange(values, 0, 1), 4); // v. 8
testVarintParceler(Arrays.copyOfRange(values, 0, 2), 4); // v. 16
testVarintParceler(Arrays.copyOfRange(values, 0, 3), 4); // v. 24
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
index 88b9522d4cb1..7ef1a3fd0d83 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
@@ -263,7 +263,7 @@ public class BatteryStatsNoteTest extends TestCase {
clocks.realtime = clocks.uptime = 220;
bi.noteLongPartialWakelockFinish(name, historyName, ISOLATED_UID);
- final BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory();
+ final BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory(0, 0);
BatteryStats.HistoryItem item;
@@ -319,7 +319,7 @@ public class BatteryStatsNoteTest extends TestCase {
clocks.realtime = clocks.uptime = 220;
bi.noteLongPartialWakelockFinish(name, historyName, ISOLATED_UID);
- final BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory();
+ final BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory(0, 0);
BatteryStats.HistoryItem item;
@@ -933,7 +933,7 @@ public class BatteryStatsNoteTest extends TestCase {
clocks.realtime = clocks.uptime = 5000;
bi.noteAlarmFinishLocked("foo", null, UID);
- BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory();
+ BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory(0, 0);
HistoryItem item;
assertThat(item = iterator.next()).isNotNull();
@@ -972,7 +972,7 @@ public class BatteryStatsNoteTest extends TestCase {
clocks.realtime = clocks.uptime = 5000;
bi.noteAlarmFinishLocked("foo", ws, UID);
- BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory();
+ BatteryStatsHistoryIterator iterator = bi.iterateBatteryStatsHistory(0, 0);
HistoryItem item;
assertThat(item = iterator.next()).isNotNull();
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
new file mode 100644
index 000000000000..f2ee6dbf4ed6
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.when;
+
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.CpuScalingPolicies;
+import com.android.internal.os.PowerProfile;
+import com.android.internal.os.PowerStats;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CpuPowerStatsCollectorTest {
+ private final MockClock mMockClock = new MockClock();
+ private final HandlerThread mHandlerThread = new HandlerThread("test");
+ private Handler mHandler;
+ private CpuPowerStatsCollector mCollector;
+ private PowerStats mCollectedStats;
+ @Mock
+ private PowerProfile mPowerProfile;
+ @Mock
+ private CpuPowerStatsCollector.KernelCpuStatsReader mMockKernelCpuStatsReader;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mHandlerThread.start();
+ mHandler = mHandlerThread.getThreadHandler();
+ when(mPowerProfile.getCpuPowerBracketCount()).thenReturn(2);
+ when(mPowerProfile.getCpuPowerBracketForScalingStep(0, 0)).thenReturn(0);
+ when(mPowerProfile.getCpuPowerBracketForScalingStep(0, 1)).thenReturn(1);
+ mCollector = new CpuPowerStatsCollector(new CpuScalingPolicies(
+ new SparseArray<>() {{
+ put(0, new int[]{0});
+ }},
+ new SparseArray<>() {{
+ put(0, new int[]{1, 12});
+ }}),
+ mPowerProfile, mHandler, mMockKernelCpuStatsReader, 60_000, mMockClock);
+ mCollector.addConsumer(stats -> mCollectedStats = stats);
+ mCollector.setEnabled(true);
+ }
+
+ @Test
+ public void collectStats() {
+ mockKernelCpuStats(new SparseArray<>() {{
+ put(42, new long[]{100, 200});
+ put(99, new long[]{300, 600});
+ }}, 0, 1234);
+
+ mMockClock.uptime = 1000;
+ mCollector.forceSchedule();
+ waitForIdle();
+
+ assertThat(mCollectedStats.durationMs).isEqualTo(1234);
+ assertThat(mCollectedStats.uidStats.get(42)).isEqualTo(new long[]{100, 200});
+ assertThat(mCollectedStats.uidStats.get(99)).isEqualTo(new long[]{300, 600});
+
+ mockKernelCpuStats(new SparseArray<>() {{
+ put(42, new long[]{123, 234});
+ put(99, new long[]{345, 678});
+ }}, 1234, 3421);
+
+ mMockClock.uptime = 2000;
+ mCollector.forceSchedule();
+ waitForIdle();
+
+ assertThat(mCollectedStats.durationMs).isEqualTo(3421 - 1234);
+ assertThat(mCollectedStats.uidStats.get(42)).isEqualTo(new long[]{23, 34});
+ assertThat(mCollectedStats.uidStats.get(99)).isEqualTo(new long[]{45, 78});
+ }
+
+ private void mockKernelCpuStats(SparseArray<long[]> uidToCpuStats,
+ long expectedLastUpdateTimestampMs, long newLastUpdateTimestampMs) {
+ when(mMockKernelCpuStatsReader.nativeReadCpuStats(
+ any(CpuPowerStatsCollector.KernelCpuStatsCallback.class),
+ any(int[].class), anyLong(), any(long[].class)))
+ .thenAnswer(invocation -> {
+ CpuPowerStatsCollector.KernelCpuStatsCallback callback =
+ invocation.getArgument(0);
+ int[] powerBucketIndexes = invocation.getArgument(1);
+ long lastTimestamp = invocation.getArgument(2);
+ long[] tempStats = invocation.getArgument(3);
+
+ assertThat(powerBucketIndexes).isEqualTo(new int[]{0, 1});
+ assertThat(lastTimestamp / 1000000L).isEqualTo(expectedLastUpdateTimestampMs);
+ assertThat(tempStats).hasLength(2);
+
+ for (int i = 0; i < uidToCpuStats.size(); i++) {
+ int uid = uidToCpuStats.keyAt(i);
+ long[] cpuStats = uidToCpuStats.valueAt(i);
+ System.arraycopy(cpuStats, 0, tempStats, 0, tempStats.length);
+ callback.processUidStats(uid, tempStats);
+ }
+ return newLastUpdateTimestampMs * 1000000L; // Nanoseconds
+ });
+ }
+
+ private void waitForIdle() {
+ ConditionVariable done = new ConditionVariable();
+ mHandler.post(done::open);
+ done.block();
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
new file mode 100644
index 000000000000..38a5d1943f8b
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.fail;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.provider.DeviceConfig;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.UiDevice;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+import com.android.server.power.optimization.Flags;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CpuPowerStatsCollectorValidationTest {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ private static final int WORK_DURATION_MS = 2000;
+ private static final String TEST_PKG = "com.android.coretests.apps.bstatstestapp";
+ private static final String TEST_ACTIVITY = TEST_PKG + ".TestActivity";
+ private static final String EXTRA_KEY_CMD_RECEIVER = "cmd_receiver";
+ private static final int START_ACTIVITY_TIMEOUT_MS = 2000;
+
+ private Context mContext;
+ private UiDevice mUiDevice;
+ private DeviceConfig.Properties mBackupFlags;
+ private int mTestPkgUid;
+
+ @Before
+ public void setup() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_STREAMLINED_BATTERY_STATS)
+ public void totalTimeInPowerBrackets() throws Exception {
+ dumpCpuStats(); // For the side effect of capturing the baseline.
+
+ doSomeWork();
+
+ long duration = 0;
+ long[] stats = null;
+
+ String[] cpuStatsDump = dumpCpuStats();
+ Pattern durationPattern = Pattern.compile("duration=([0-9]*)");
+ Pattern uidPattern = Pattern.compile("UID " + mTestPkgUid + ": \\[([0-9,\\s]*)]");
+ for (String line : cpuStatsDump) {
+ Matcher durationMatcher = durationPattern.matcher(line);
+ if (durationMatcher.find()) {
+ duration = Long.parseLong(durationMatcher.group(1));
+ }
+ Matcher uidMatcher = uidPattern.matcher(line);
+ if (uidMatcher.find()) {
+ String[] strings = uidMatcher.group(1).split(", ");
+ stats = new long[strings.length];
+ for (int i = 0; i < strings.length; i++) {
+ stats[i] = Long.parseLong(strings[i]);
+ }
+ }
+ }
+ if (stats == null) {
+ fail("No CPU stats for " + mTestPkgUid + " (" + TEST_PKG + ")");
+ }
+
+ assertThat(duration).isAtLeast(WORK_DURATION_MS);
+
+ long total = Arrays.stream(stats).sum();
+ assertThat(total).isAtLeast((long) (WORK_DURATION_MS * 0.8));
+ }
+
+ private String[] dumpCpuStats() throws Exception {
+ String dump = executeCmdSilent("dumpsys batterystats --sample");
+ String[] lines = dump.split("\n");
+ for (int i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("CpuPowerStatsCollector")) {
+ return Arrays.copyOfRange(lines, i + 1, lines.length);
+ }
+ }
+ return new String[0];
+ }
+
+ private void doSomeWork() throws Exception {
+ final ICmdReceiver receiver;
+ receiver = ICmdReceiver.Stub.asInterface(startActivity());
+ try {
+ receiver.doSomeWork(WORK_DURATION_MS);
+ } finally {
+ receiver.finishHost();
+ }
+ }
+
+ private IBinder startActivity() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Intent launchIntent = new Intent().setComponent(
+ new ComponentName(TEST_PKG, TEST_ACTIVITY));
+ final Bundle extras = new Bundle();
+ final IBinder[] binders = new IBinder[1];
+ extras.putBinder(EXTRA_KEY_CMD_RECEIVER, new ICmdCallback.Stub() {
+ @Override
+ public void onLaunched(IBinder receiver) {
+ binders[0] = receiver;
+ latch.countDown();
+ }
+ });
+ launchIntent.putExtras(extras).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(launchIntent);
+ if (latch.await(START_ACTIVITY_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ if (binders[0] == null) {
+ fail("Receiver binder should not be null");
+ }
+ return binders[0];
+ } else {
+ fail("Timed out waiting for the test activity to start; testUid=" + mTestPkgUid);
+ }
+ return null;
+ }
+
+ private String executeCmdSilent(String cmd) throws Exception {
+ return mUiDevice.executeShellCommand(cmd).trim();
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
index 28f4799656b7..6cd08653bc33 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
@@ -26,7 +26,6 @@ import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerAttribution;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
-import android.os.BatteryStats;
import android.util.SparseArray;
import android.util.SparseLongArray;
@@ -238,17 +237,6 @@ public final class EnergyConsumerSnapshotTest {
}
@Test
- public void getMeasuredEnergyDetails() {
- final EnergyConsumerSnapshot snapshot = new EnergyConsumerSnapshot(ALL_ID_CONSUMER_MAP);
- snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0);
- EnergyConsumerDeltaData delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1);
- BatteryStats.EnergyConsumerDetails details = snapshot.getEnergyConsumerDetails(delta);
- assertThat(details.consumers).hasLength(4);
- assertThat(details.chargeUC).isEqualTo(new long[]{2667, 3200000, 0, 0});
- assertThat(details.toString()).isEqualTo("DISPLAY=2667 HPU=3200000 GPU=0 IPU &_=0");
- }
-
- @Test
public void testUpdateAndGetDelta_updatesCameraCharge() {
EnergyConsumer cameraConsumer =
createEnergyConsumer(7, 0, EnergyConsumerType.CAMERA, "CAMERA");
@@ -266,12 +254,8 @@ public final class EnergyConsumerSnapshotTest {
createEnergyConsumerResult(cameraConsumer.id, 90_000, null, null),
};
EnergyConsumerDeltaData delta = snapshot.updateAndGetDelta(result1, VOLTAGE_1);
-
- // Verify that the delta between the two results is reported.
- BatteryStats.EnergyConsumerDetails details = snapshot.getEnergyConsumerDetails(delta);
- assertThat(details.consumers).hasLength(1);
long expectedDeltaUC = calculateChargeConsumedUC(60_000, VOLTAGE_1, 90_000, VOLTAGE_1);
- assertThat(details.chargeUC[0]).isEqualTo(expectedDeltaUC);
+ assertThat(delta.cameraChargeUC).isEqualTo(expectedDeltaUC);
}
private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index 6d3f1f27b572..4150972ab69a 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -119,6 +119,13 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return MOBILE_RADIO_POWER_STATE_UPDATE_FREQ_MS;
}
+ public MockBatteryStatsImpl setBatteryStatsConfig(BatteryStatsConfig config) {
+ synchronized (this) {
+ mBatteryStatsConfig = config;
+ }
+ return this;
+ }
+
public MockBatteryStatsImpl setNetworkStats(NetworkStats networkStats) {
mNetworkStats = networkStats;
return this;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
new file mode 100644
index 000000000000..4ecee9fe7d23
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.os.BatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.MultiStateStats;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MultiStateStatsTest {
+
+ public static final int DIMENSION_COUNT = 2;
+
+ @Test
+ public void compositeStateIndex_allEnabled() {
+ MultiStateStats.Factory factory = makeFactory(true, true, true);
+ assertThatCpuPerformanceStatsFactory(factory)
+ .hasSerialStateCount(BatteryConsumer.PROCESS_STATE_COUNT * 4)
+ .haveDifferentSerialStates(
+ state(false, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, false, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(true, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, false, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_BACKGROUND));
+ }
+
+ @Test
+ public void compositeStateIndex_procStateTrackingDisabled() {
+ MultiStateStats.Factory factory = makeFactory(true, false, true);
+ assertThatCpuPerformanceStatsFactory(factory)
+ .hasSerialStateCount(4)
+ .haveDifferentSerialStates(
+ state(false, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_FOREGROUND))
+ .haveSameSerialStates(
+ state(false, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, false, BatteryConsumer.PROCESS_STATE_BACKGROUND))
+ .haveSameSerialStates(
+ state(false, true, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_BACKGROUND))
+ .haveSameSerialStates(
+ state(true, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, false, BatteryConsumer.PROCESS_STATE_BACKGROUND))
+ .haveSameSerialStates(
+ state(true, true, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_BACKGROUND));
+ }
+
+ @Test
+ public void compositeStateIndex_screenTrackingDisabled() {
+ MultiStateStats.Factory factory = makeFactory(true, true, false);
+ assertThatCpuPerformanceStatsFactory(factory)
+ .hasSerialStateCount(BatteryConsumer.PROCESS_STATE_COUNT * 2)
+ .haveDifferentSerialStates(
+ state(false, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(true, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_BACKGROUND))
+ .haveSameSerialStates(
+ state(false, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_FOREGROUND))
+ .haveSameSerialStates(
+ state(true, false, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_BACKGROUND));
+ }
+
+ @Test
+ public void compositeStateIndex_allDisabled() {
+ MultiStateStats.Factory factory = makeFactory(false, false, false);
+ assertThatCpuPerformanceStatsFactory(factory)
+ .hasSerialStateCount(1)
+ .haveSameSerialStates(
+ state(false, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, false, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(false, true, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(true, false, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, false, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ state(true, true, BatteryConsumer.PROCESS_STATE_BACKGROUND));
+ }
+
+ @Test
+ public void tooManyStates() {
+ // 4 bits needed to represent
+ String[] labels = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"};
+ // 4 * 10 = 40 bits needed to represent the composite state
+ MultiStateStats.States[] states = new MultiStateStats.States[10];
+ for (int i = 0; i < states.length; i++) {
+ states[i] = new MultiStateStats.States(true, labels);
+ }
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> new MultiStateStats.Factory(DIMENSION_COUNT, states));
+ assertThat(e.getMessage()).contains("40");
+ }
+
+ @Test
+ public void multiStateStats_aggregation() {
+ MultiStateStats.Factory factory = makeFactory(true, true, false);
+ MultiStateStats multiStateStats = factory.create();
+ multiStateStats.setState(0 /* batteryState */, 1 /* on */, 1000);
+ multiStateStats.setState(1 /* procState */, BatteryConsumer.PROCESS_STATE_FOREGROUND, 1000);
+ multiStateStats.setState(2 /* screenState */, 0 /* off */, 1000);
+
+ multiStateStats.increment(new long[]{100, 200}, 1000);
+
+ multiStateStats.setState(0 /* batteryState */, 0 /* off */, 2000);
+ multiStateStats.setState(2 /* screenState */, 1 /* on */, 2000); // untracked
+
+ multiStateStats.increment(new long[]{300, 500}, 3000);
+
+ multiStateStats.setState(1 /* procState */, BatteryConsumer.PROCESS_STATE_BACKGROUND, 4000);
+
+ multiStateStats.increment(new long[]{200, 200}, 5000);
+
+ long[] stats = new long[DIMENSION_COUNT];
+ multiStateStats.getStats(stats, new int[]{0, BatteryConsumer.PROCESS_STATE_FOREGROUND, 0});
+ // (400 - 100) * 0.5 + (600 - 400) * 0.5
+ assertThat(stats).isEqualTo(new long[]{250, 350});
+
+ multiStateStats.getStats(stats, new int[]{1, BatteryConsumer.PROCESS_STATE_FOREGROUND, 0});
+ // (400 - 100) * 0.5 + (600 - 400) * 0
+ assertThat(stats).isEqualTo(new long[]{150, 250});
+
+ // Note that screen state does not affect the result, as it is untracked
+ multiStateStats.getStats(stats, new int[]{0, BatteryConsumer.PROCESS_STATE_BACKGROUND, 1});
+ // (400 - 100) * 0 + (600 - 400) * 0.5
+ assertThat(stats).isEqualTo(new long[]{100, 100});
+
+ multiStateStats.getStats(stats, new int[]{1, BatteryConsumer.PROCESS_STATE_BACKGROUND, 0});
+ // Never been in this composite state
+ assertThat(stats).isEqualTo(new long[]{0, 0});
+ }
+
+ @Test
+ public void dump() {
+ MultiStateStats.Factory factory = makeFactory(true, true, false);
+ MultiStateStats multiStateStats = factory.create();
+ multiStateStats.setState(0 /* batteryState */, 0 /* off */, 1000);
+ multiStateStats.setState(1 /* procState */, BatteryConsumer.PROCESS_STATE_FOREGROUND, 1000);
+ multiStateStats.setState(2 /* screenState */, 0 /* off */, 1000);
+ multiStateStats.setState(0 /* batteryState */, 1 /* on */, 2000);
+ multiStateStats.setState(1 /* procState */, BatteryConsumer.PROCESS_STATE_BACKGROUND, 3000);
+ multiStateStats.increment(new long[]{100, 200}, 5000);
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, true);
+ multiStateStats.dump(pw);
+ assertThat(sw.toString()).isEqualTo(
+ "plugged-in fg [25, 50]\n"
+ + "on-battery fg [25, 50]\n"
+ + "on-battery bg [50, 100]\n"
+ );
+ }
+
+ private static MultiStateStats.Factory makeFactory(boolean trackBatteryState,
+ boolean trackProcState, boolean trackScreenState) {
+ return new MultiStateStats.Factory(DIMENSION_COUNT,
+ new MultiStateStats.States(trackBatteryState, "plugged-in", "on-battery"),
+ new MultiStateStats.States(trackProcState,
+ BatteryConsumer.processStateToString(
+ BatteryConsumer.PROCESS_STATE_UNSPECIFIED),
+ BatteryConsumer.processStateToString(
+ BatteryConsumer.PROCESS_STATE_FOREGROUND),
+ BatteryConsumer.processStateToString(
+ BatteryConsumer.PROCESS_STATE_BACKGROUND),
+ BatteryConsumer.processStateToString(
+ BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE),
+ BatteryConsumer.processStateToString(
+ BatteryConsumer.PROCESS_STATE_CACHED)),
+ new MultiStateStats.States(trackScreenState, "screen-off", "plugged-in"));
+ }
+
+ private FactorySubject assertThatCpuPerformanceStatsFactory(
+ MultiStateStats.Factory factory) {
+ FactorySubject subject = new FactorySubject();
+ subject.mFactory = factory;
+ return subject;
+ }
+
+ private static class FactorySubject {
+ private MultiStateStats.Factory mFactory;
+
+ FactorySubject hasSerialStateCount(int stateCount) {
+ assertThat(mFactory.getSerialStateCount()).isEqualTo(stateCount);
+ return this;
+ }
+
+ public FactorySubject haveDifferentSerialStates(State... states) {
+ int[] serialStates = getSerialStates(states);
+ assertWithMessage("Expected all to be different: " + Arrays.toString(serialStates))
+ .that(Arrays.stream(serialStates).distinct().toArray())
+ .hasLength(states.length);
+ return this;
+ }
+
+ public FactorySubject haveSameSerialStates(State... states) {
+ int[] serialStates = getSerialStates(states);
+ assertWithMessage("Expected all to be the same: " + Arrays.toString(serialStates))
+ .that(Arrays.stream(serialStates).distinct().toArray())
+ .hasLength(1);
+ return this;
+ }
+
+ private int[] getSerialStates(State[] states) {
+ int[] serialStates = new int[states.length];
+ for (int i = 0; i < states.length; i++) {
+ serialStates[i] = mFactory.getSerialState(
+ new int[]{
+ states[i].batteryState ? 0 : 1,
+ states[i].procstate,
+ states[i].screenState ? 0 : 1
+ });
+ }
+ return serialStates;
+ }
+ }
+
+ private State state(boolean batteryState, boolean screenState, int procstate) {
+ State state = new State();
+ state.batteryState = batteryState;
+ state.screenState = screenState;
+ state.procstate = procstate;
+ return state;
+ }
+
+ private static class State {
+ public boolean batteryState;
+ public boolean screenState;
+ public int procstate;
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
new file mode 100644
index 000000000000..47de44324ae1
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.BatteryStatsHistory;
+import com.android.internal.os.PowerStats;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PowerStatsAggregatorTest {
+ private static final int TEST_POWER_COMPONENT = 77;
+ private static final int TEST_UID = 42;
+
+ private final MockClock mClock = new MockClock();
+ private long mStartTime;
+ private BatteryStatsHistory mHistory;
+ private PowerStatsAggregator mAggregator;
+ private int mAggregatedStatsCount;
+
+ @Before
+ public void setup() throws ParseException {
+ mHistory = new BatteryStatsHistory(32, 1024,
+ mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock);
+ mStartTime = new SimpleDateFormat("yyyy-MM-dd HH:mm")
+ .parse("2008-09-23 08:00").getTime();
+ mClock.currentTime = mStartTime;
+
+ PowerStatsAggregator.Builder builder = new PowerStatsAggregator.Builder(mHistory);
+ builder.trackPowerComponent(TEST_POWER_COMPONENT)
+ .trackDeviceStates(
+ PowerStatsAggregator.STATE_POWER,
+ PowerStatsAggregator.STATE_SCREEN)
+ .trackUidStates(
+ PowerStatsAggregator.STATE_POWER,
+ PowerStatsAggregator.STATE_SCREEN,
+ PowerStatsAggregator.STATE_PROCESS_STATE);
+ mAggregator = builder.build();
+ }
+
+ @Test
+ public void stateUpdates() {
+ mHistory.forceRecordAllHistory();
+ mHistory.recordBatteryState(mClock.realtime, mClock.uptime, 10, /* plugged */ true);
+ mHistory.recordStateStartEvent(mClock.realtime, mClock.uptime,
+ BatteryStats.HistoryItem.STATE_SCREEN_ON_FLAG);
+ mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime, TEST_UID,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND);
+
+ advance(1000);
+
+ PowerStats.Descriptor descriptor =
+ new PowerStats.Descriptor(TEST_POWER_COMPONENT, "majorDrain", 1, 1,
+ new PersistableBundle());
+ PowerStats powerStats = new PowerStats(descriptor);
+ powerStats.stats = new long[]{10000};
+ powerStats.uidStats.put(TEST_UID, new long[]{1234});
+ mHistory.recordPowerStats(mClock.realtime, mClock.uptime, powerStats);
+
+ mHistory.recordBatteryState(mClock.realtime, mClock.uptime, 90, /* plugged */ false);
+ mHistory.recordStateStopEvent(mClock.realtime, mClock.uptime,
+ BatteryStats.HistoryItem.STATE_SCREEN_ON_FLAG);
+
+ advance(1000);
+
+ mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime, TEST_UID,
+ BatteryConsumer.PROCESS_STATE_BACKGROUND);
+
+ advance(3000);
+
+ powerStats.stats = new long[]{20000};
+ powerStats.uidStats.put(TEST_UID, new long[]{4444});
+ mHistory.recordPowerStats(mClock.realtime, mClock.uptime, powerStats);
+
+ mAggregator.aggregateBatteryStats(0, 0, stats -> {
+ assertThat(mAggregatedStatsCount++).isEqualTo(0);
+ assertThat(stats.getStartTime()).isEqualTo(mStartTime);
+ assertThat(stats.getDuration()).isEqualTo(5000);
+
+ long[] values = new long[1];
+
+ PowerComponentAggregatedPowerStats powerComponentStats = stats.getPowerComponentStats(
+ TEST_POWER_COMPONENT);
+
+ assertThat(powerComponentStats.getDeviceStats(values, new int[]{
+ PowerStatsAggregator.POWER_STATE_OTHER,
+ PowerStatsAggregator.SCREEN_STATE_ON}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{10000});
+
+ assertThat(powerComponentStats.getDeviceStats(values, new int[]{
+ PowerStatsAggregator.POWER_STATE_BATTERY,
+ PowerStatsAggregator.SCREEN_STATE_OTHER}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{20000});
+
+ assertThat(powerComponentStats.getUidStats(values, TEST_UID, new int[]{
+ PowerStatsAggregator.POWER_STATE_OTHER,
+ PowerStatsAggregator.SCREEN_STATE_ON,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{1234});
+
+ assertThat(powerComponentStats.getUidStats(values, TEST_UID, new int[]{
+ PowerStatsAggregator.POWER_STATE_BATTERY,
+ PowerStatsAggregator.SCREEN_STATE_OTHER,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{1111});
+
+ assertThat(powerComponentStats.getUidStats(values, TEST_UID, new int[]{
+ PowerStatsAggregator.POWER_STATE_BATTERY,
+ PowerStatsAggregator.SCREEN_STATE_OTHER,
+ BatteryConsumer.PROCESS_STATE_BACKGROUND}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{3333});
+ });
+ }
+
+ @Test
+ public void incompatiblePowerStats() {
+ mHistory.forceRecordAllHistory();
+ mHistory.recordBatteryState(mClock.realtime, mClock.uptime, 10, /* plugged */ true);
+ mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime, TEST_UID,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND);
+
+ advance(1000);
+
+ PowerStats.Descriptor descriptor =
+ new PowerStats.Descriptor(TEST_POWER_COMPONENT, "majorDrain", 1, 1,
+ new PersistableBundle());
+ PowerStats powerStats = new PowerStats(descriptor);
+ powerStats.stats = new long[]{10000};
+ powerStats.uidStats.put(TEST_UID, new long[]{1234});
+ mHistory.recordPowerStats(mClock.realtime, mClock.uptime, powerStats);
+
+ mHistory.recordBatteryState(mClock.realtime, mClock.uptime, 90, /* plugged */ false);
+
+ advance(1000);
+
+ descriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, "majorDrain", 1, 1,
+ PersistableBundle.forPair("something", "changed"));
+ powerStats = new PowerStats(descriptor);
+ powerStats.stats = new long[]{20000};
+ powerStats.uidStats.put(TEST_UID, new long[]{4444});
+ mHistory.recordPowerStats(mClock.realtime, mClock.uptime, powerStats);
+
+ advance(1000);
+
+ mHistory.recordBatteryState(mClock.realtime, mClock.uptime, 50, /* plugged */ true);
+
+ mAggregator.aggregateBatteryStats(0, 0, stats -> {
+ long[] values = new long[1];
+
+ PowerComponentAggregatedPowerStats powerComponentStats =
+ stats.getPowerComponentStats(TEST_POWER_COMPONENT);
+
+ if (mAggregatedStatsCount == 0) {
+ assertThat(stats.getStartTime()).isEqualTo(mStartTime);
+ assertThat(stats.getDuration()).isEqualTo(2000);
+
+ assertThat(powerComponentStats.getDeviceStats(values, new int[]{
+ PowerStatsAggregator.POWER_STATE_OTHER,
+ PowerStatsAggregator.SCREEN_STATE_ON}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{10000});
+ assertThat(powerComponentStats.getUidStats(values, TEST_UID, new int[]{
+ PowerStatsAggregator.POWER_STATE_OTHER,
+ PowerStatsAggregator.SCREEN_STATE_ON,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{1234});
+ } else if (mAggregatedStatsCount == 1) {
+ assertThat(stats.getStartTime()).isEqualTo(mStartTime + 2000);
+ assertThat(stats.getDuration()).isEqualTo(1000);
+
+ assertThat(powerComponentStats.getDeviceStats(values, new int[]{
+ PowerStatsAggregator.POWER_STATE_BATTERY,
+ PowerStatsAggregator.SCREEN_STATE_ON}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{20000});
+ assertThat(powerComponentStats.getUidStats(values, TEST_UID, new int[]{
+ PowerStatsAggregator.POWER_STATE_BATTERY,
+ PowerStatsAggregator.SCREEN_STATE_ON,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND}))
+ .isTrue();
+ assertThat(values).isEqualTo(new long[]{4444});
+ } else {
+ fail();
+ }
+ mAggregatedStatsCount++;
+ });
+ }
+
+ private void advance(long durationMs) {
+ mClock.realtime += durationMs;
+ mClock.uptime += durationMs;
+ mClock.currentTime += durationMs;
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
new file mode 100644
index 000000000000..330f698277f8
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.PowerStats;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PowerStatsCollectorTest {
+ private final MockClock mMockClock = new MockClock();
+ private final HandlerThread mHandlerThread = new HandlerThread("test");
+ private Handler mHandler;
+ private PowerStatsCollector mCollector;
+ private PowerStats mCollectedStats;
+
+ @Before
+ public void setup() {
+ mHandlerThread.start();
+ mHandler = mHandlerThread.getThreadHandler();
+ mCollector = new PowerStatsCollector(mHandler,
+ 60000,
+ mMockClock) {
+ @Override
+ protected PowerStats collectStats() {
+ return new PowerStats(new PowerStats.Descriptor(0, 0, 0, new PersistableBundle()));
+ }
+ };
+ mCollector.addConsumer(stats -> mCollectedStats = stats);
+ mCollector.setEnabled(true);
+ }
+
+ @Test
+ public void throttlePeriod() {
+ mMockClock.uptime = 1000;
+ mCollector.schedule();
+ waitForIdle();
+
+ assertThat(mCollectedStats).isNotNull();
+
+ mMockClock.uptime += 1000;
+ mCollectedStats = null;
+ mCollector.schedule(); // Should be throttled
+ waitForIdle();
+
+ assertThat(mCollectedStats).isNull();
+
+ // Should be allowed to run
+ mMockClock.uptime += 100_000;
+ mCollector.schedule();
+ waitForIdle();
+
+ assertThat(mCollectedStats).isNotNull();
+ }
+
+ private void waitForIdle() {
+ ConditionVariable done = new ConditionVariable();
+ mHandler.post(done::open);
+ done.block();
+ }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 92ff7ab86247..20d8a5d1efeb 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -68,6 +68,7 @@ android_test {
"ActivityContext",
"coretests-aidl",
"securebox",
+ "flag-junit",
],
libs: [
diff --git a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
index 90df786e5970..45e7f3512975 100644
--- a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
@@ -34,10 +34,10 @@ import libcore.io.IoUtils;
*/
public class CertBlacklisterTest extends AndroidTestCase {
- private static final String BLACKLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
+ private static final String DENYLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
- public static final String PUBKEY_PATH = BLACKLIST_ROOT + "pubkey_blacklist.txt";
- public static final String SERIAL_PATH = BLACKLIST_ROOT + "serial_blacklist.txt";
+ public static final String PUBKEY_PATH = DENYLIST_ROOT + "pubkey_blacklist.txt";
+ public static final String SERIAL_PATH = DENYLIST_ROOT + "serial_blacklist.txt";
public static final String PUBKEY_KEY = "pubkey_blacklist";
public static final String SERIAL_KEY = "serial_blacklist";
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 0a8c5703abcd..9fe743da225e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -30,6 +30,7 @@ import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
@@ -43,6 +44,7 @@ import static org.mockito.Mockito.when;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
+import android.content.pm.PackageManager;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
@@ -252,7 +254,11 @@ public class FullScreenMagnificationGestureHandlerTest {
detectTripleTap, detectShortcutTrigger,
mWindowMagnificationPromptController, DISPLAY_0,
mMockFullScreenMagnificationVibrationHelper);
- h.setSinglePanningEnabled(true);
+ if (isWatch()) {
+ h.setSinglePanningEnabled(true);
+ } else {
+ h.setSinglePanningEnabled(false);
+ }
mHandler = new TestHandler(h.mDetectingState, mClock) {
@Override
protected String messageToString(Message m) {
@@ -569,6 +575,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
public void testActionUpNotAtEdge_singlePanningState_detectingState() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
goFromStateIdleTo(STATE_SINGLE_PANNING);
send(upEvent());
@@ -579,6 +586,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
public void testScroll_SinglePanningDisabled_delegatingState() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
mMgh.setSinglePanningEnabled(false);
goFromStateIdleTo(STATE_ACTIVATED);
@@ -591,6 +599,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
@FlakyTest
public void testScroll_singleHorizontalPanningAndAtEdge_leftEdgeOverscroll() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
goFromStateIdleTo(STATE_SINGLE_PANNING);
float centerY =
(INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.bottom) / 2.0f;
@@ -614,6 +623,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
@FlakyTest
public void testScroll_singleHorizontalPanningAndAtEdge_rightEdgeOverscroll() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
goFromStateIdleTo(STATE_SINGLE_PANNING);
float centerY =
(INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.bottom) / 2.0f;
@@ -637,6 +647,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
@FlakyTest
public void testScroll_singleVerticalPanningAndAtEdge_verticalOverscroll() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
goFromStateIdleTo(STATE_SINGLE_PANNING);
float centerX =
(INITIAL_MAGNIFICATION_BOUNDS.right + INITIAL_MAGNIFICATION_BOUNDS.left) / 2.0f;
@@ -658,6 +669,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
public void testScroll_singlePanningAndAtEdge_noOverscroll() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
goFromStateIdleTo(STATE_SINGLE_PANNING);
float centerY =
(INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.bottom) / 2.0f;
@@ -679,6 +691,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
public void testScroll_singleHorizontalPanningAndAtEdge_vibrate() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
goFromStateIdleTo(STATE_SINGLE_PANNING);
mFullScreenMagnificationController.setCenter(
DISPLAY_0,
@@ -702,6 +715,7 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
public void testScroll_singleVerticalPanningAndAtEdge_doNotVibrate() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
goFromStateIdleTo(STATE_SINGLE_PANNING);
mFullScreenMagnificationController.setCenter(
DISPLAY_0,
@@ -868,6 +882,10 @@ public class FullScreenMagnificationGestureHandlerTest {
mFullScreenMagnificationController.onUserContextChanged(DISPLAY_0);
}
+ private boolean isWatch() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+
/**
* Asserts that {@link #mMgh the handler} is in the given {@code state}
*/
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 9ca84d33998c..ce15c6d30531 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -218,7 +218,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void updateRuleSet_notSystemApp() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp(false);
Rule rule =
new Rule(
@@ -237,7 +237,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void updateRuleSet_authorized() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
Rule rule =
new Rule(
@@ -251,7 +251,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void updateRuleSet_correctMethodCall() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
IntentSender mockReceiver = mock(IntentSender.class);
List<Rule> rules =
@@ -271,7 +271,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void updateRuleSet_fail() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
doThrow(new IOException()).when(mIntegrityFileManager).writeRules(any(), any(), any());
IntentSender mockReceiver = mock(IntentSender.class);
@@ -292,7 +292,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void broadcastReceiverRegistration() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
ArgumentCaptor<IntentFilter> intentFilterCaptor =
ArgumentCaptor.forClass(IntentFilter.class);
@@ -308,7 +308,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void handleBroadcast_correctArgs() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -345,7 +345,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void handleBroadcast_correctArgs_multipleCerts() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -368,7 +368,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void handleBroadcast_correctArgs_sourceStamp() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -393,7 +393,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void handleBroadcast_allow() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -412,7 +412,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void handleBroadcast_reject() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -438,7 +438,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void handleBroadcast_notInitialized() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
when(mIntegrityFileManager.initialized()).thenReturn(false);
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
@@ -459,7 +459,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void verifierAsInstaller_skipIntegrityVerification() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
setIntegrityCheckIncludesRuleProvider(false);
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
@@ -480,7 +480,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void getCurrentRules() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
Rule rule = new Rule(IntegrityFormula.Application.packageNameEquals("package"), Rule.DENY);
when(mIntegrityFileManager.readRules(any())).thenReturn(Arrays.asList(rule));
@@ -490,7 +490,7 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void getWhitelistedRuleProviders_returnsEmptyForNonSystemApps() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp(false);
assertThat(mService.getWhitelistedRuleProviders()).isEmpty();
@@ -498,13 +498,13 @@ public class AppIntegrityManagerServiceImplTest {
@Test
public void getWhitelistedRuleProviders() throws Exception {
- whitelistUsAsRuleProvider();
+ allowlistUsAsRuleProvider();
makeUsSystemApp();
assertThat(mService.getWhitelistedRuleProviders()).containsExactly(TEST_FRAMEWORK_PACKAGE);
}
- private void whitelistUsAsRuleProvider() {
+ private void allowlistUsAsRuleProvider() {
Resources mockResources = mock(Resources.class);
when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
.thenReturn(new String[] {TEST_FRAMEWORK_PACKAGE});
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index e5909a42ea10..80fb5e3f950d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -512,7 +512,7 @@ public class KeySyncTaskTest {
verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
.isTestOnlyCertificateAlias(eq(TEST_ROOT_CERT_ALIAS));
- // no whitelists check
+ // no allowlists check
verify(mTestOnlyInsecureCertificateHelper, never())
.doesCredentialSupportInsecureMode(anyInt(), any());
verify(mTestOnlyInsecureCertificateHelper, never())
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 07d4065e4f8f..a8e3c7e4ef6d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -117,7 +117,7 @@ public class UserSystemPackageInstallerTest {
for (int userId : mRemoveUsers) {
um.removeUser(userId);
}
- setUserTypePackageWhitelistMode(mOriginalWhitelistMode);
+ setUserTypePackageAllowlistMode(mOriginalWhitelistMode);
}
/**
@@ -184,7 +184,7 @@ public class UserSystemPackageInstallerTest {
}
}
- final ArrayMap<String, Long> expectedOutput = getNewPackageToWhitelistedBitSetMap();
+ final ArrayMap<String, Long> expectedOutput = getNewPackageToAllowlistedBitSetMap();
expectedOutput.put("com.android.package1", expectedUserTypeBitSet1);
expectedOutput.put("com.android.package2", expectedUserTypeBitSet2);
expectedOutput.put("com.android.package3", expectedUserTypeBitSet3);
@@ -227,7 +227,7 @@ public class UserSystemPackageInstallerTest {
}
};
- final ArrayMap<String, Long> expectedOutput = getNewPackageToWhitelistedBitSetMap();
+ final ArrayMap<String, Long> expectedOutput = getNewPackageToAllowlistedBitSetMap();
expectedOutput.put("com.android.package2", 0L);
expectedOutput.put("com.android.package3", 0L);
expectedOutput.put("com.android.package4", 0L);
@@ -340,7 +340,7 @@ public class UserSystemPackageInstallerTest {
public void testPackagesForCreateUser_full() {
final String userTypeToCreate = USER_TYPE_FULL_SECONDARY;
final long userTypeMask = mUserSystemPackageInstaller.getUserTypeMask(userTypeToCreate);
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
PackageManager pm = mContext.getPackageManager();
final SystemConfig sysConfig = new SystemConfigTestClass(true);
@@ -384,7 +384,7 @@ public class UserSystemPackageInstallerTest {
*/
@Test
public void testInstallOverlayPackagesExplicitMode() {
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
final String[] userTypes = new String[]{"type"};
final long maskOfType = 0b0001L;
@@ -453,49 +453,49 @@ public class UserSystemPackageInstallerTest {
*/
@Test
public void testSetWhitelistEnabledMode() {
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
assertTrue(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
assertTrue(mUserSystemPackageInstaller.isIgnoreOtaMode());
- setUserTypePackageWhitelistMode(
+ setUserTypePackageAllowlistMode(
USER_TYPE_PACKAGE_WHITELIST_MODE_LOG | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertTrue(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
@@ -503,7 +503,7 @@ public class UserSystemPackageInstallerTest {
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
- setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
+ setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
| USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
@@ -513,7 +513,7 @@ public class UserSystemPackageInstallerTest {
}
/** Sets the allowlist mode to the desired value via adb's setprop. */
- private void setUserTypePackageWhitelistMode(int mode) {
+ private void setUserTypePackageAllowlistMode(int mode) {
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
try {
String result = uiDevice.executeShellCommand(String.format("setprop %s %d",
@@ -526,7 +526,7 @@ public class UserSystemPackageInstallerTest {
}
/** @see UserSystemPackageInstaller#mWhitelistedPackagesForUserTypes */
- private ArrayMap<String, Long> getNewPackageToWhitelistedBitSetMap() {
+ private ArrayMap<String, Long> getNewPackageToAllowlistedBitSetMap() {
final ArrayMap<String, Long> pkgBitSetMap = new ArrayMap<>();
// "android" is always treated as allowlisted for all types, regardless of the xml file.
pkgBitSetMap.put("android", ~0L);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index 560a91974692..20c0b0a3af66 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -529,7 +529,6 @@ class AndroidPackageParsingValidationTest {
"}",
":",
"?",
- "-",
"%",
"^",
"*",
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 9fca513e50b9..ee3ab9744fdd 100644
--- a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -149,6 +149,32 @@ public class HintManagerServiceTest {
}
@Test
+ public void testCreateHintSession_exceedsLimit() throws Exception {
+ HintManagerService service = createService();
+ IBinder token1 = new Binder();
+ IBinder token2 = new Binder();
+
+ for (int i = 0; i < 10; i++) {
+ IHintSession a = service.getBinderServiceInstance().createHintSession(token1,
+ SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
+ assertNotNull(a);
+ }
+
+ for (int i = 0; i < 10; i++) {
+ IHintSession b = service.getBinderServiceInstance().createHintSession(token2,
+ SESSION_TIDS_B, DEFAULT_TARGET_DURATION);
+ assertNotNull(b);
+ }
+
+ assertThrows(IllegalStateException.class,
+ () -> service.getBinderServiceInstance().createHintSession(token1, SESSION_TIDS_A,
+ DEFAULT_TARGET_DURATION));
+ assertThrows(IllegalStateException.class,
+ () -> service.getBinderServiceInstance().createHintSession(token2, SESSION_TIDS_B,
+ DEFAULT_TARGET_DURATION));
+ }
+
+ @Test
public void testPauseResumeHintSession() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/OWNERS b/services/tests/servicestests/src/com/android/server/power/hint/OWNERS
new file mode 100644
index 000000000000..c28c07a234b3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/hint/OWNERS
@@ -0,0 +1,2 @@
+include /ADPF_OWNERS
+
diff --git a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
index 22d383a84177..fc5213cba2e2 100644
--- a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
@@ -82,7 +82,7 @@ public class TestHandler extends Handler {
uptimeMillis = uptimeMillis - SystemClock.uptimeMillis() + mClock.getAsLong();
}
- // post a dummy queue entry to keep track of message removal
+ // post a sentinel queue entry to keep track of message removal
return super.sendMessageAtTime(msg, Long.MAX_VALUE)
&& mMessages.add(new MsgInfo(Message.obtain(msg), uptimeMillis, mMessageCount));
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 57aa0b96a56a..579bbc8a417a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6044,6 +6044,49 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testVisitUris_styleExtrasWithoutStyle() {
+ Notification notification = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .build();
+
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(
+ personWithIcon("content://user"))
+ .addHistoricMessage(new Notification.MessagingStyle.Message("Heyhey!",
+ System.currentTimeMillis(),
+ personWithIcon("content://historicalMessenger")))
+ .addMessage(new Notification.MessagingStyle.Message("Are you there",
+ System.currentTimeMillis(),
+ personWithIcon("content://messenger")))
+ .setShortcutIcon(
+ Icon.createWithContentUri("content://conversationShortcut"));
+ messagingStyle.addExtras(notification.extras); // Instead of Builder.setStyle(style).
+
+ Notification.CallStyle callStyle = Notification.CallStyle.forOngoingCall(
+ personWithIcon("content://caller"),
+ PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE))
+ .setVerificationIcon(Icon.createWithContentUri("content://callVerification"));
+ callStyle.addExtras(notification.extras); // Same.
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ notification.visitUris(visitor);
+
+ verify(visitor).accept(eq(Uri.parse("content://user")));
+ verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
+ verify(visitor).accept(eq(Uri.parse("content://messenger")));
+ verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
+ verify(visitor).accept(eq(Uri.parse("content://caller")));
+ verify(visitor).accept(eq(Uri.parse("content://callVerification")));
+ }
+
+ private static Person personWithIcon(String iconUri) {
+ return new Person.Builder()
+ .setName("Mr " + iconUri)
+ .setIcon(Icon.createWithContentUri(iconUri))
+ .build();
+ }
+
+ @Test
public void testVisitUris_wearableExtender() {
Icon actionIcon = Icon.createWithContentUri("content://media/action");
Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 81d939f1f05f..9b745f5aaf4f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -115,6 +115,7 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
+import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -209,6 +210,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Mock Context mContext;
@Mock ZenModeHelper mMockZenModeHelper;
@Mock AppOpsManager mAppOpsManager;
+ @Mock ManagedServices.UserProfiles mUserProfiles;
@Mock PermissionManager mPermissionManager;
private NotificationManager.Policy mTestNotificationPolicy;
@@ -327,10 +329,12 @@ public class PreferencesHelperTest extends UiServiceTestCase {
when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
.thenReturn(appPermissions);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0}));
+
mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager,
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
mStatsEventBuilderFactory, false);
resetZenModeHelper();
@@ -678,7 +682,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_oldXml_migrates() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
+ mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ true);
String xml = "<ranking version=\"2\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1
@@ -743,9 +748,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_oldXml_backup_migratesWhenPkgInstalled() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
-
when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
when(mPm.getPackageUidAsUser("pkg3", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
@@ -822,7 +824,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
+ mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ true);
String xml = "<ranking version=\"3\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -879,7 +882,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_newXml_permissionNotificationOff() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
+ mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ false);
String xml = "<ranking version=\"3\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -936,7 +940,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
+ mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ true);
String xml = "<ranking version=\"4\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -991,9 +996,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_oldXml_migration_NoUid() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
-
when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
String xml = "<ranking version=\"2\">\n"
+ "<package name=\"something\" show_badge=\"true\">\n"
@@ -1024,9 +1026,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_newXml_noMigration_NoUid() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
-
when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
String xml = "<ranking version=\"3\">\n"
+ "<package name=\"something\" show_badge=\"true\">\n"
@@ -1056,9 +1055,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForNonBackup_postMigration() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
-
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false));
@@ -1142,9 +1138,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForBackup_postMigration() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
-
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false));
@@ -1234,9 +1227,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForBackup_postMigration_noExternal() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
-
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false));
appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false));
@@ -1319,9 +1309,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForBackup_postMigration_noLocalSettings() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
-
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false));
@@ -1533,7 +1520,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
new FileNotFoundException("")).thenReturn(resId);
mHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
+ mStatsEventBuilderFactory, false);
NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -2477,9 +2465,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.syncChannelsBypassingDnd();
// create notification channel that can bypass dnd, but app is blocked
@@ -2508,9 +2493,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.syncChannelsBypassingDnd();
// create notification channel that can bypass dnd, but app is blocked
@@ -2533,9 +2515,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.syncChannelsBypassingDnd();
// create notification channel that can bypass dnd, but app is blocked
@@ -2588,9 +2567,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.syncChannelsBypassingDnd();
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean());
@@ -2602,15 +2578,58 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// start notification policy off with mAreChannelsBypassingDnd = false
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean());
resetZenModeHelper();
}
@Test
+ public void syncChannelsBypassingDnd_includesProfilesOfCurrentUser() throws Exception {
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0, 10}));
+ when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true);
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+ when(mPm.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn(appInfo);
+
+ NotificationChannel withBypass = new NotificationChannel("1", "with", IMPORTANCE_DEFAULT);
+ withBypass.setBypassDnd(true);
+ NotificationChannel withoutBypass = new NotificationChannel("2", "without",
+ IMPORTANCE_DEFAULT);
+ withoutBypass.setBypassDnd(false);
+ mHelper.createNotificationChannel("com.example", UserHandle.getUid(0, 444), withoutBypass,
+ false, false, Process.SYSTEM_UID, true);
+ mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass,
+ false, false, Process.SYSTEM_UID, true);
+
+ mHelper.syncChannelsBypassingDnd();
+
+ assertThat(mHelper.areChannelsBypassingDnd()).isTrue();
+ }
+
+ @Test
+ public void syncChannelsBypassingDnd_excludesOtherUsers() throws Exception {
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0}));
+ when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true);
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+ when(mPm.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn(appInfo);
+
+ NotificationChannel withBypass = new NotificationChannel("1", "with", IMPORTANCE_DEFAULT);
+ withBypass.setBypassDnd(true);
+ NotificationChannel withoutBypass = new NotificationChannel("2", "without",
+ IMPORTANCE_DEFAULT);
+ withoutBypass.setBypassDnd(false);
+ mHelper.createNotificationChannel("com.example", UserHandle.getUid(0, 444), withoutBypass,
+ false, false, Process.SYSTEM_UID, true);
+ mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass,
+ false, false, Process.SYSTEM_UID, true);
+
+ mHelper.syncChannelsBypassingDnd();
+
+ assertThat(mHelper.areChannelsBypassingDnd()).isFalse();
+ }
+
+ @Test
public void testCreateDeletedChannel() throws Exception {
long[] vibration = new long[]{100, 67, 145, 156};
NotificationChannel channel =
@@ -3705,9 +3724,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ "</package>\n"
+ "</ranking>\n";
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
+
loadByteArrayXml(preQXml.getBytes(), true, USER_SYSTEM);
assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -3719,9 +3736,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -3789,9 +3803,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.canShowBadge(PKG_O, UID_O);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -3802,9 +3813,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -3816,9 +3824,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -3832,9 +3837,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
@@ -3888,9 +3890,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.getAppLockedFields(PKG_O, UID_O));
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
@@ -3926,9 +3925,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.getAppLockedFields(PKG_O, UID_O));
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
@@ -4584,10 +4580,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testPlaceholderConversationId_shortcutRequired() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+ "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>"
@@ -4604,10 +4596,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testNormalConversationId_shortcutRequired() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+ "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"other\"/>"
@@ -4624,10 +4612,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testNoConversationId_shortcutRequired() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+ "<channel id=\"id\" name=\"hi\" importance=\"3\"/>"
@@ -4644,10 +4628,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testDeleted_noTime() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+ "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\"/>"
@@ -4664,13 +4644,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testDeleted_twice() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
mHelper.createNotificationChannel(
PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false,
UID_P, false);
+
assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id",
UID_P, false));
assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id",
@@ -4679,10 +4656,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testDeleted_recentTime() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
mHelper.createNotificationChannel(
PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false,
UID_P, false);
@@ -4698,9 +4671,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
null);
parser.nextTag();
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.readXml(parser, true, USER_SYSTEM);
NotificationChannel nc = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
@@ -4710,10 +4680,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testUnDelete_time() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
mHelper.createNotificationChannel(
PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false,
UID_P, false);
@@ -4732,10 +4698,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testDeleted_longTime() throws Exception {
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mPermissionManager, mLogger,
- mAppOpsManager, mStatsEventBuilderFactory, false);
-
long time = System.currentTimeMillis() - (DateUtils.DAY_IN_MILLIS * 30);
final String xml = "<ranking version=\"1\">\n"
diff --git a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
index 6f6540627f67..05a1482b9be6 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
@@ -112,7 +112,7 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase {
// Show assistant.
mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_ASSISTANT);
sendKey(KEYCODE_POWER, true);
- mPhoneWindowManager.assertAssistLaunch();
+ mPhoneWindowManager.assertSearchManagerLaunchAssist();
// Show global actions.
mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_GLOBAL_ACTIONS);
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 3bb86a7bfecb..b9492e9b1b77 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -170,10 +170,15 @@ public class SingleKeyGestureTests {
}
private void pressKey(int keyCode, long pressTime, boolean interactive) {
+ pressKey(keyCode, pressTime, interactive, false /* defaultDisplayOn */);
+ }
+
+ private void pressKey(
+ int keyCode, long pressTime, boolean interactive, boolean defaultDisplayOn) {
long eventTime = SystemClock.uptimeMillis();
final KeyEvent keyDown = new KeyEvent(eventTime, eventTime, ACTION_DOWN,
keyCode, 0 /* repeat */, 0 /* metaState */);
- mDetector.interceptKey(keyDown, interactive);
+ mDetector.interceptKey(keyDown, interactive, defaultDisplayOn);
// keep press down.
try {
@@ -186,7 +191,7 @@ public class SingleKeyGestureTests {
final KeyEvent keyUp = new KeyEvent(eventTime, eventTime, ACTION_UP,
keyCode, 0 /* repeat */, 0 /* metaState */);
- mDetector.interceptKey(keyUp, interactive);
+ mDetector.interceptKey(keyUp, interactive, defaultDisplayOn);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
index c433e644a6a0..eab8757b7331 100644
--- a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
@@ -16,11 +16,15 @@
package com.android.server.policy;
+import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS;
import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS;
import static android.view.KeyEvent.KEYCODE_STEM_PRIMARY;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT;
import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS;
+import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY;
+import android.content.ComponentName;
import android.provider.Settings;
import org.junit.Test;
@@ -32,6 +36,9 @@ import org.junit.Test;
* atest WmTests:StemKeyGestureTests
*/
public class StemKeyGestureTests extends ShortcutKeyTestBase {
+
+ private static final String TEST_TARGET_ACTIVITY = "com.android.server.policy/.TestActivity";
+
/**
* Stem single key should not launch behavior during set up.
*/
@@ -63,6 +70,57 @@ public class StemKeyGestureTests extends ShortcutKeyTestBase {
mPhoneWindowManager.assertOpenAllAppView();
}
+ /**
+ * Stem single key should not launch behavior during set up.
+ */
+ @Test
+ public void stemSingleKey_launchTargetActivity() {
+ overrideBehavior(
+ STEM_PRIMARY_BUTTON_SHORT_PRESS,
+ SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.overrideStartActivity();
+ mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+ mPhoneWindowManager.assumeResolveActivityNotNull();
+
+ ComponentName targetComponent = ComponentName.unflattenFromString(TEST_TARGET_ACTIVITY);
+ mPhoneWindowManager.overrideStemPressTargetActivity(targetComponent);
+
+ sendKey(KEYCODE_STEM_PRIMARY);
+
+ mPhoneWindowManager.assertActivityTargetLaunched(targetComponent);
+ }
+
+ @Test
+ public void stemLongKey_triggerSearchServiceToLaunchAssist() {
+ overrideBehavior(
+ STEM_PRIMARY_BUTTON_LONG_PRESS,
+ LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.setupAssistForLaunch();
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+
+ sendKey(KEYCODE_STEM_PRIMARY, /* longPress= */ true);
+ mPhoneWindowManager.assertSearchManagerLaunchAssist();
+ }
+
+ @Test
+ public void stemLongKey_whenNoSearchService_triggerStatusBarToStartAssist() {
+ overrideBehavior(
+ STEM_PRIMARY_BUTTON_LONG_PRESS,
+ LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.setupAssistForLaunch();
+ mPhoneWindowManager.overrideSearchManager(null);
+ mPhoneWindowManager.overrideStatusBarManagerInternal();
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+
+ sendKey(KEYCODE_STEM_PRIMARY, /* longPress= */ true);
+ mPhoneWindowManager.assertStatusBarStartAssist();
+ }
+
+
private void overrideBehavior(String key, int expectedBehavior) {
Settings.Global.putLong(mContext.getContentResolver(), key, expectedBehavior);
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index ef3a6edf9759..bc8f06a48ffb 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -59,9 +59,11 @@ import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.SearchManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.hardware.SensorPrivacyManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
@@ -230,6 +232,7 @@ class TestPhoneWindowManager {
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mSensorPrivacyManager).when(mContext).getSystemService(
eq(SensorPrivacyManager.class));
+ doReturn(mSearchManager).when(mContext).getSystemService(eq(SearchManager.class));
doReturn(false).when(mPackageManager).hasSystemFeature(any());
try {
doThrow(new PackageManager.NameNotFoundException("test")).when(mPackageManager)
@@ -355,11 +358,7 @@ class TestPhoneWindowManager {
case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
break;
case LONG_PRESS_POWER_ASSISTANT:
- doNothing().when(mPhoneWindowManager).sendCloseSystemWindows();
- doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
- doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
- doReturn(mSearchManager).when(mContext)
- .getSystemService(eq(Context.SEARCH_SERVICE));
+ setupAssistForLaunch();
mPhoneWindowManager.mLongPressOnPowerAssistantTimeoutMs = 500;
break;
}
@@ -433,6 +432,22 @@ class TestPhoneWindowManager {
doReturn(isShowing).when(mKeyguardServiceDelegate).isShowing();
}
+ void setupAssistForLaunch() {
+ doNothing().when(mPhoneWindowManager).sendCloseSystemWindows();
+ doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
+ doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+ }
+
+ void overrideSearchManager(SearchManager searchManager) {
+ mPhoneWindowManager.mSearchManager = searchManager;
+ }
+
+ void assumeResolveActivityNotNull() {
+ ResolveInfo resolveInfo = new ResolveInfo();
+ doReturn(resolveInfo).when(mPackageManager).resolveActivity(any(), anyInt());
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ }
+
void overrideKeyEventSource(int vendorId, int productId) {
InputDevice device = new InputDevice.Builder().setId(1).setVendorId(vendorId).setProductId(
productId).setSources(InputDevice.SOURCE_KEYBOARD).setKeyboardType(
@@ -458,6 +473,10 @@ class TestPhoneWindowManager {
doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
}
+ void overrideStemPressTargetActivity(ComponentName component) {
+ mPhoneWindowManager.mPrimaryShortPressTargetActivity = component;
+ }
+
/**
* Below functions will check the policy behavior could be invoked.
*/
@@ -517,7 +536,7 @@ class TestPhoneWindowManager {
.interceptPowerKeyDown(any(), anyBoolean(), any());
}
- void assertAssistLaunch() {
+ void assertSearchManagerLaunchAssist() {
waitForIdle();
verify(mSearchManager, timeout(SHORTCUT_KEY_DELAY_MILLIS)).launchAssist(any());
}
@@ -540,6 +559,11 @@ class TestPhoneWindowManager {
verify(mStatusBarManagerInternal).showRecentApps(anyBoolean());
}
+ void assertStatusBarStartAssist() {
+ waitForIdle();
+ verify(mStatusBarManagerInternal).startAssist(any());
+ }
+
void assertSwitchKeyboardLayout(int direction) {
waitForIdle();
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
@@ -613,6 +637,14 @@ class TestPhoneWindowManager {
.startActivityAsUser(any(Intent.class), any(), any(UserHandle.class));
}
+ void assertActivityTargetLaunched(ComponentName targetActivity) {
+ waitForIdle();
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, timeout(TEST_SINGLE_KEY_DELAY_MILLIS))
+ .startActivityAsUser(intentCaptor.capture(), isNull(), any(UserHandle.class));
+ Assert.assertEquals(targetActivity, intentCaptor.getValue().getComponent());
+ }
+
void assertShortcutLogged(int vendorId, int productId, KeyboardLogEvent logEvent,
int expectedKey, int expectedModifierState, String errorMsg) {
waitForIdle();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java
index ce1a46bdd9c0..1f9e8c2ce8ca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java
@@ -16,10 +16,8 @@
package com.android.server.wm;
-import static android.Manifest.permission.ACCESS_SURFACE_FLINGER;
-import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
-import static android.server.wm.CtsWindowInfoUtils.waitForWindowVisible;
import static android.server.wm.CtsWindowInfoUtils.waitForWindowFocus;
+import static android.server.wm.CtsWindowInfoUtils.waitForWindowVisible;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.junit.Assert.assertTrue;
@@ -78,17 +76,11 @@ public class SurfaceControlViewHostTests {
@Before
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
-
- // ACCESS_SURFACE_FLINGER is necessary to call waitForWindow
- // INTERNAL_SYSTEM_WINDOW is necessary to add SCVH with no host parent
- mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(ACCESS_SURFACE_FLINGER,
- INTERNAL_SYSTEM_WINDOW);
mActivity = mActivityRule.launchActivity(null);
}
@After
public void tearDown() {
- mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
CommonUtils.waitUntilActivityRemoved(mActivity);
}
@@ -102,14 +94,15 @@ public class SurfaceControlViewHostTests {
mView2 = new Button(mActivity);
mInstrumentation.runOnMainSync(() -> {
- TestWindowlessWindowManager wwm = new TestWindowlessWindowManager(
- mActivity.getResources().getConfiguration(), sc, null);
-
try {
mActivity.attachToSurfaceView(sc);
} catch (InterruptedException e) {
}
+ TestWindowlessWindowManager wwm = new TestWindowlessWindowManager(
+ mActivity.getResources().getConfiguration(), sc,
+ mActivity.mSurfaceView.getHostToken());
+
mScvh1 = new SurfaceControlViewHost(mActivity, mActivity.getDisplay(),
wwm, "requestFocusWithMultipleWindows");
mScvh2 = new SurfaceControlViewHost(mActivity, mActivity.getDisplay(),
@@ -130,11 +123,13 @@ public class SurfaceControlViewHostTests {
assertTrue("Failed to wait for view1", waitForWindowVisible(mView1));
assertTrue("Failed to wait for view2", waitForWindowVisible(mView2));
- WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ IWindow window = IWindow.Stub.asInterface(mActivity.mSurfaceView.getWindowToken());
+
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window,
mScvh1.getFocusGrantToken(), true);
assertTrue("Failed to gain focus for view1", waitForWindowFocus(mView1, true));
- WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window,
mScvh2.getFocusGrantToken(), true);
assertTrue("Failed to gain focus for view2", waitForWindowFocus(mView2, true));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 07cdfafdd341..873d09b42c83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -39,6 +39,7 @@ import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_SYNC;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.isIndependent;
@@ -1190,6 +1191,7 @@ public class TransitionTests extends WindowTestsBase {
final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar");
makeWindowVisible(statusBar);
mDisplayContent.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs);
+ final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "navBar");
final ActivityRecord app = createActivityRecord(mDisplayContent);
final Transition transition = app.mTransitionController.createTransition(TRANSIT_OPEN);
app.mTransitionController.requestStartTransition(transition, app.getTask(),
@@ -1219,9 +1221,17 @@ public class TransitionTests extends WindowTestsBase {
mDisplayContent.mTransitionController.dispatchLegacyAppTransitionFinished(app);
assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
+ // The bar was invisible so it is not handled by the controller. But if it becomes visible
+ // and drawn before the transition starts,
+ assertFalse(asyncRotationController.isTargetToken(navBar.mToken));
+ navBar.finishDrawing(null /* postDrawTransaction */, Integer.MAX_VALUE);
+ assertTrue(asyncRotationController.isTargetToken(navBar.mToken));
+
player.startTransition();
// Non-app windows should not be collected.
assertFalse(mDisplayContent.mTransitionController.isCollecting(statusBar.mToken));
+ // Avoid DeviceStateController disturbing the test by triggering another rotation change.
+ doReturn(false).when(mDisplayContent).updateRotationUnchecked();
onRotationTransactionReady(player, mWm.mTransactionFactory.get()).onTransactionCommitted();
assertEquals(ROTATION_ANIMATION_SEAMLESS, player.mLastReady.getChange(
@@ -2390,6 +2400,37 @@ public class TransitionTests extends WindowTestsBase {
assertFalse(controller.isCollecting());
}
+ @Test
+ public void testNoSyncFlagIfOneTrack() {
+ final TransitionController controller = mAtm.getTransitionController();
+ final TestTransitionPlayer player = registerTestTransitionPlayer();
+
+ mSyncEngine = createTestBLASTSyncEngine();
+ controller.setSyncEngine(mSyncEngine);
+
+ final Transition transitA = createTestTransition(TRANSIT_OPEN, controller);
+ final Transition transitB = createTestTransition(TRANSIT_OPEN, controller);
+ final Transition transitC = createTestTransition(TRANSIT_OPEN, controller);
+
+ controller.startCollectOrQueue(transitA, (deferred) -> {});
+ controller.startCollectOrQueue(transitB, (deferred) -> {});
+ controller.startCollectOrQueue(transitC, (deferred) -> {});
+
+ // Verify that, as-long as there is <= 1 track, we won't get a SYNC flag
+ transitA.start();
+ transitA.setAllReady();
+ mSyncEngine.tryFinishForTest(transitA.getSyncId());
+ assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+ transitB.start();
+ transitB.setAllReady();
+ mSyncEngine.tryFinishForTest(transitB.getSyncId());
+ assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+ transitC.start();
+ transitC.setAllReady();
+ mSyncEngine.tryFinishForTest(transitC.getSyncId());
+ assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 5bdcdf4d63ef..eb0a1e1a40bc 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -361,18 +361,6 @@ public final class Call {
"android.telecom.extra.DIAGNOSTIC_MESSAGE";
/**
- * Event reported from the Telecom stack to indicate that the {@link Connection} is not able to
- * find any network and likely will not get connected. Upon receiving this event, the dialer
- * app should show satellite SOS button if satellite is provisioned.
- * <p>
- * The dialer app receives this event via
- * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
- * @hide
- */
- public static final String EVENT_DISPLAY_SOS_MESSAGE =
- "android.telecom.event.DISPLAY_SOS_MESSAGE";
-
- /**
* Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
* call because they have declined to answer it. This typically means that they are unable
* to answer the call at this time and would prefer it be sent to voicemail.
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4907134ffe1f..13e5ff15f1d8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -10408,7 +10408,7 @@ public class CarrierConfigManager {
sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
new int[] {4 /* BUSY */});
sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
- sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
+ sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 5000);
sDefaults.putStringArray(KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
CellSignalStrengthLte.USE_RSRP);
@@ -10518,7 +10518,7 @@ public class CarrierConfigManager {
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
"eHRPD", new int[]{10, 400, 600, 800, 1000});
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
- "TD_SCDMA", new int[]{1, 100, 500, 1000});
+ "TD_SCDMA", new int[]{1, 50, 100, 500, 1000});
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
"iDEN", new int[]{1, 2, 10, 50, 100});
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
@@ -10536,7 +10536,7 @@ public class CarrierConfigManager {
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
"EvDo_0", new int[]{300, 600, 1000, 1500, 2000});
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
- "1xRTT", new int[]{50, 60, 70, 80});
+ "1xRTT", new int[]{50, 60, 70, 80, 90});
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
"EDGE", new int[]{154, 169, 183, 192, 267});
auto_data_switch_rat_signal_score_string_bundle.putIntArray(
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 6997f3c79bc3..f9844bcc677d 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -362,7 +362,6 @@ public final class DisconnectCause {
/**
* Indicates that the call was unable to be made because the satellite modem is enabled.
- * @hide
*/
public static final int SATELLITE_ENABLED = 82;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index baacb574bde3..12ab5c32ad49 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3396,15 +3396,11 @@ public class SubscriptionManager {
if (iSub != null) {
groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug);
} else {
- if (!isSystemProcess()) {
- throw new IllegalStateException("telephony service is null.");
- }
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
loge("createSubscriptionGroup RemoteException " + ex);
- if (!isSystemProcess()) {
- ex.rethrowAsRuntimeException();
- }
+ ex.rethrowAsRuntimeException();
}
return groupUuid;
@@ -3446,15 +3442,11 @@ public class SubscriptionManager {
if (iSub != null) {
iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug);
} else {
- if (!isSystemProcess()) {
- throw new IllegalStateException("telephony service is null.");
- }
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
loge("addSubscriptionsIntoGroup RemoteException " + ex);
- if (!isSystemProcess()) {
- ex.rethrowAsRuntimeException();
- }
+ ex.rethrowAsRuntimeException();
}
}
@@ -3497,15 +3489,11 @@ public class SubscriptionManager {
if (iSub != null) {
iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, callingPackage);
} else {
- if (!isSystemProcess()) {
- throw new IllegalStateException("telephony service is null.");
- }
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
loge("removeSubscriptionsFromGroup RemoteException " + ex);
- if (!isSystemProcess()) {
- ex.rethrowAsRuntimeException();
- }
+ ex.rethrowAsRuntimeException();
}
}
@@ -3562,6 +3550,11 @@ public class SubscriptionManager {
}
}
+ // TODO(b/296125268) Really this method should throw, but it's common enough that for
+ // system callers it's worth having a little magic for the system process until it's
+ // made safer.
+ if (result == null) result = Collections.emptyList();
+
return result;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f1ee76e1ed94..5f67441b533c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -76,7 +76,9 @@ import android.provider.Settings.SettingNotFoundException;
import android.service.carrier.CarrierIdentifier;
import android.service.carrier.CarrierService;
import android.sysprop.TelephonyProperties;
+import android.telecom.Call;
import android.telecom.CallScreeningService;
+import android.telecom.Connection;
import android.telecom.InCallService;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
@@ -1186,6 +1188,17 @@ public class TelephonyManager {
"android.telephony.event.EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION";
/**
+ * Event reported from the Telephony stack to indicate that the {@link Connection} is not
+ * able to find any network and likely will not get connected. Upon receiving this event,
+ * the dialer app should show satellite SOS button if satellite is provisioned.
+ * <p>
+ * The dialer app receives this event via
+ * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
+ */
+ public static final String EVENT_DISPLAY_SOS_MESSAGE =
+ "android.telephony.event.DISPLAY_SOS_MESSAGE";
+
+ /**
* Integer extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} which indicates
* the type of supplementary service notification which occurred.
* Will be either
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java b/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
index 0f694c293330..fe9126003967 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
+++ b/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
@@ -18,5 +18,5 @@ package com.android.apkverity.feature_x;
import android.app.Activity;
-/** Dummy class just to generate some dex */
+/** Placeholder class just to generate some dex */
public class DummyActivity extends Activity {}
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java b/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
index 837c7be37504..a7bd771400c0 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
+++ b/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
@@ -18,5 +18,5 @@ package com.android.apkverity;
import android.app.Activity;
-/** Dummy class just to generate some dex */
+/** Placeholder class just to generate some dex */
public class DummyActivity extends Activity {}
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java
index 001396527267..4b7ca5306bfb 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java
@@ -113,7 +113,7 @@ public class GraphExporter {
getDotName(target.getFilter().getName()) + ":" +
getDotName(target.getName()) + "_IN;\n" );
} else {
- // Found a unconnected output port, add dummy node
+ // Found a unconnected output port, add placeholder node
String color = filter.getSignature().getOutputPortInfo(portName).isRequired()
? "red" : "blue"; // red for unconnected, required ports
dotFile.write(" " +
@@ -131,7 +131,7 @@ public class GraphExporter {
if(target != null) {
// Found a connection -- nothing to do, connections have been written out above
} else {
- // Found a unconnected input port, add dummy node
+ // Found a unconnected input port, add placeholder node
String color = filter.getSignature().getInputPortInfo(portName).isRequired()
? "red" : "blue"; // red for unconnected, required ports
dotFile.write(" " +
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java
index b7212f982bce..6bd6c18f1c0a 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java
@@ -66,9 +66,9 @@ public class MffContext {
/**
* On older Android versions the Camera may need a SurfaceView to render into in order to
- * function. You may specify a dummy SurfaceView here if you do not want the context to
+ * function. You may specify a placeholder SurfaceView here if you do not want the context to
* create its own view. Note, that your view may or may not be used. You cannot rely on
- * your dummy view to be used by the Camera. If you pass null, no dummy view will be used.
+ * your placeholder view to be used by the Camera. If you pass null, no placeholder view will be used.
* In this case your application may not run correctly on older devices if you use the
* camera. This flag has no effect if you do not require the camera.
*/
@@ -104,7 +104,7 @@ public class MffContext {
/** The current context state. */
private State mState = new State();
- /** A dummy SurfaceView that is required for Camera operation on older devices. */
+ /** A placeholder SurfaceView that is required for Camera operation on older devices. */
private SurfaceView mDummySurfaceView = null;
/** Handler to execute code in the context's thread, such as issuing callbacks. */
@@ -126,7 +126,7 @@ public class MffContext {
* multiple MffContexts, however data between them cannot be shared. The context must be
* created in a thread with a Looper (such as the main/UI thread).
*
- * On older versions of Android, the MffContext may create a visible dummy view for the
+ * On older versions of Android, the MffContext may create a visible placeholder view for the
* camera to render into. This is a 1x1 SurfaceView that is placed into the top-left corner.
*
* @param context The application context to attach the MffContext to.
@@ -142,7 +142,7 @@ public class MffContext {
* multiple MffContexts, however data between them cannot be shared. The context must be
* created in a thread with a Looper (such as the main/UI thread).
*
- * On older versions of Android, the MffContext may create a visible dummy view for the
+ * On older versions of Android, the MffContext may create a visible placeholder view for the
* camera to render into. This is a 1x1 SurfaceView that is placed into the top-left corner.
* You may alternatively specify your own SurfaceView in the configuration.
*
diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
index e995a26ea5c9..2ca91fbc1d3d 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
@@ -16,7 +16,7 @@
package com.android.dcl;
-/** Dummy class which is built into a jar purely so we can pass it to DexClassLoader. */
+/** Placeholder class which is built into a jar purely so we can pass it to DexClassLoader. */
public final class Simple {
public Simple() {}
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 704798e11016..f867c989232d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -70,7 +70,7 @@
<activity android:name=".SeamlessRotationActivity"
android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
android:theme="@style/CutoutShortEdges"
- android:configChanges="orientation|screenSize"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="SeamlessActivity"
android:exported="true">
<intent-filter>
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
index c9b5c96c9920..12556bcf7ded 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
@@ -154,7 +154,7 @@ public final class ImeStressTestUtil {
* <p>The given {@code pred} will be called on the main thread.
*/
public static void waitOnMainUntil(String message, Callable<Boolean> pred) {
- eventually(() -> assertWithMessage(message).that(pred.call()).isTrue(), TIMEOUT);
+ eventually(() -> assertWithMessage(message).that(callOnMainSync(pred)).isTrue(), TIMEOUT);
}
/** Waits until IME is shown, or throws on timeout. */
diff --git a/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java
index 731be8e3d9f0..a77950fe4a2d 100644
--- a/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java
+++ b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java
@@ -24,7 +24,7 @@ import android.os.ServiceManager;
import com.android.internal.compat.IPlatformCompat;
/**
- * This is a dummy API to test gating
+ * This is a placeholder API to test gating
*
* @hide
*/
@@ -36,7 +36,7 @@ public class DummyApi {
public static final long CHANGE_SYSTEM_SERVER = 666016;
/**
- * Dummy method
+ * Placeholder method
* @return "A" if change is enabled, "B" otherwise.
*/
public static String dummyFunc() {
@@ -47,7 +47,7 @@ public class DummyApi {
}
/**
- * Dummy combined method
+ * Placeholder combined method
* @return "0" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is disabled,
"1" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is enabled,
"2" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is disabled,
@@ -68,7 +68,7 @@ public class DummyApi {
}
/**
- * Dummy api using system server API.
+ * Placeholder api using system server API.
*/
public static boolean dummySystemServer(Context context) {
IPlatformCompat platformCompat = IPlatformCompat.Stub
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 3567c08d0285..cc6cebf88907 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -469,7 +469,7 @@ public class SoundTriggerTestService extends Service {
}
}
- // Create a few dummy models if we didn't load anything.
+ // Create a few placeholder models if we didn't load anything.
if (!loadedModel) {
Properties dummyModelProperties = new Properties();
for (String name : new String[]{"1", "2", "3"}) {
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java
index ba12acb2c877..2b605c594ce8 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java
@@ -18,6 +18,7 @@ package com.google.android.test.windowinsetstests;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
+
import static java.lang.Math.max;
import static java.lang.Math.min;
@@ -41,11 +42,11 @@ import android.view.WindowInsetsAnimationController;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
+import androidx.appcompat.app.AppCompatActivity;
+
import java.util.ArrayList;
import java.util.List;
-import androidx.appcompat.app.AppCompatActivity;
-
public class ChatActivity extends AppCompatActivity {
private View mRoot;
@@ -148,7 +149,7 @@ public class ChatActivity extends AppCompatActivity {
inset = min(inset, shown);
mAnimationController.setInsetsAndAlpha(
Insets.of(0, 0, 0, inset),
- 1f, (inset - start) / (float)(end - start));
+ 1f, start == end ? 1f : (inset - start) / (float) (end - start));
}
});
diff --git a/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java b/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
index 9999aba37d8d..673c73aa2aac 100644
--- a/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
+++ b/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
@@ -22,7 +22,7 @@ package com.android.test.libs.system_ext;
public class LibsSystemExtTest {
/**
- * Dummy method for testing.
+ * Placeholder method for testing.
*/
public static void test() {
}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 899d26818548..b94d14fd4b75 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -219,7 +219,7 @@ bool AaptLocaleValue::initFromFilterString(const String8& str) {
if (numTags >= 1) {
const String8& lang = parts[0];
if (isAlpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
- setLanguage(lang.string());
+ setLanguage(lang.c_str());
valid = true;
}
}
@@ -232,11 +232,11 @@ bool AaptLocaleValue::initFromFilterString(const String8& str) {
const String8& part2 = parts[1];
if ((part2.length() == 2 && isAlpha(part2)) ||
(part2.length() == 3 && isNumber(part2))) {
- setRegion(part2.string());
+ setRegion(part2.c_str());
} else if (part2.length() == 4 && isAlpha(part2)) {
- setScript(part2.string());
+ setScript(part2.c_str());
} else if (part2.length() >= 4 && part2.length() <= 8) {
- setVariant(part2.string());
+ setVariant(part2.c_str());
} else {
valid = false;
}
@@ -249,9 +249,9 @@ bool AaptLocaleValue::initFromFilterString(const String8& str) {
const String8& part3 = parts[2];
if (((part3.length() == 2 && isAlpha(part3)) ||
(part3.length() == 3 && isNumber(part3))) && script[0]) {
- setRegion(part3.string());
+ setRegion(part3.c_str());
} else if (part3.length() >= 4 && part3.length() <= 8) {
- setVariant(part3.string());
+ setVariant(part3.c_str());
} else {
valid = false;
}
@@ -262,7 +262,7 @@ bool AaptLocaleValue::initFromFilterString(const String8& str) {
const String8& part4 = parts[3];
if (part4.length() >= 4 && part4.length() <= 8) {
- setVariant(part4.string());
+ setVariant(part4.c_str());
} else {
valid = false;
}
@@ -310,7 +310,7 @@ int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int sta
break;
default:
fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n",
- part.string());
+ part.c_str());
return -1;
}
} else if (subtags.size() == 3) {
@@ -324,7 +324,7 @@ int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int sta
} else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
setRegion(subtags[1]);
} else {
- fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.string());
+ fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.c_str());
return -1;
}
@@ -341,14 +341,14 @@ int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int sta
setRegion(subtags[2]);
setVariant(subtags[3]);
} else {
- fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name: %s\n", part.string());
+ fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name: %s\n", part.c_str());
return -1;
}
return ++currentIndex;
} else {
if ((part.length() == 2 || part.length() == 3)
- && isAlpha(part) && strcmp("car", part.string())) {
+ && isAlpha(part) && strcmp("car", part.c_str())) {
setLanguage(part);
if (++currentIndex == size) {
return size;
@@ -358,8 +358,8 @@ int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int sta
}
part = parts[currentIndex];
- if (part.string()[0] == 'r' && part.length() == 3) {
- setRegion(part.string() + 1);
+ if (part.c_str()[0] == 'r' && part.length() == 3) {
+ setRegion(part.c_str() + 1);
if (++currentIndex == size) {
return size;
}
@@ -524,8 +524,8 @@ status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplic
ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
if (index >= 0 && overwriteDuplicate) {
fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
- mFiles[index]->getSourceFile().string(),
- file->getSourceFile().string());
+ mFiles[index]->getSourceFile().c_str(),
+ file->getSourceFile().c_str());
removeFile(index);
index = -1;
}
@@ -545,7 +545,7 @@ status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplic
const sp<AaptFile>& originalFile = mFiles.valueAt(index);
SourcePos(file->getSourceFile(), -1)
.error("Duplicate file.\n%s: Original is here. %s",
- originalFile->getPrintableSource().string(),
+ originalFile->getPrintableSource().c_str(),
(withoutVersion.version != 0) ? "The version qualifier may be implied." : "");
return UNKNOWN_ERROR;
}
@@ -557,21 +557,21 @@ void AaptGroup::removeFile(size_t index)
void AaptGroup::print(const String8& prefix) const
{
- printf("%s%s\n", prefix.string(), getPath().string());
+ printf("%s%s\n", prefix.c_str(), getPath().c_str());
const size_t N=mFiles.size();
size_t i;
for (i=0; i<N; i++) {
sp<AaptFile> file = mFiles.valueAt(i);
const AaptGroupEntry& e = file->getGroupEntry();
if (file->hasData()) {
- printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(),
+ printf("%s Gen: (%s) %d bytes\n", prefix.c_str(), e.toDirName(String8()).c_str(),
(int)file->getSize());
} else {
- printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(),
- file->getPrintableSource().string());
+ printf("%s Src: (%s) %s\n", prefix.c_str(), e.toDirName(String8()).c_str(),
+ file->getPrintableSource().c_str());
}
- //printf("%s File Group Entry: %s\n", prefix.string(),
- // file->getGroupEntry().toDirName(String8()).string());
+ //printf("%s File Group Entry: %s\n", prefix.c_str(),
+ // file->getGroupEntry().toDirName(String8()).c_str());
}
}
@@ -660,9 +660,9 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
{
DIR* dir = NULL;
- dir = opendir(srcDir.string());
+ dir = opendir(srcDir.c_str());
if (dir == NULL) {
- fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
+ fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.c_str(), strerror(errno));
return UNKNOWN_ERROR;
}
@@ -676,7 +676,7 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
if (entry == NULL)
break;
- if (isHidden(srcDir.string(), entry->d_name))
+ if (isHidden(srcDir.c_str(), entry->d_name))
continue;
String8 name(entry->d_name);
@@ -701,8 +701,8 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
String8 pathName(srcDir);
FileType type;
- pathName.appendPath(fileNames[i].string());
- type = getFileType(pathName.string());
+ pathName.appendPath(fileNames[i].c_str());
+ type = getFileType(pathName.c_str());
if (type == kFileTypeDirectory) {
sp<AaptDir> subdir;
bool notAdded = false;
@@ -732,7 +732,7 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
} else {
if (bundle->getVerbose())
- printf(" (ignoring non-file/dir '%s')\n", pathName.string());
+ printf(" (ignoring non-file/dir '%s')\n", pathName.c_str());
}
}
@@ -745,7 +745,7 @@ status_t AaptDir::validate() const
const size_t ND = mDirs.size();
size_t i;
for (i = 0; i < NF; i++) {
- if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
+ if (!validateFileName(mFiles.valueAt(i)->getLeaf().c_str())) {
SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
"Invalid filename. Unable to add.");
return UNKNOWN_ERROR;
@@ -753,11 +753,11 @@ status_t AaptDir::validate() const
size_t j;
for (j = i+1; j < NF; j++) {
- if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
- mFiles.valueAt(j)->getLeaf().string()) == 0) {
+ if (strcasecmp(mFiles.valueAt(i)->getLeaf().c_str(),
+ mFiles.valueAt(j)->getLeaf().c_str()) == 0) {
SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
"File is case-insensitive equivalent to: %s",
- mFiles.valueAt(j)->getPrintableSource().string());
+ mFiles.valueAt(j)->getPrintableSource().c_str());
return UNKNOWN_ERROR;
}
@@ -766,18 +766,18 @@ status_t AaptDir::validate() const
}
for (j = 0; j < ND; j++) {
- if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
- mDirs.valueAt(j)->getLeaf().string()) == 0) {
+ if (strcasecmp(mFiles.valueAt(i)->getLeaf().c_str(),
+ mDirs.valueAt(j)->getLeaf().c_str()) == 0) {
SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
"File conflicts with dir from: %s",
- mDirs.valueAt(j)->getPrintableSource().string());
+ mDirs.valueAt(j)->getPrintableSource().c_str());
return UNKNOWN_ERROR;
}
}
}
for (i = 0; i < ND; i++) {
- if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
+ if (!validateFileName(mDirs.valueAt(i)->getLeaf().c_str())) {
SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
"Invalid directory name, unable to add.");
return UNKNOWN_ERROR;
@@ -785,11 +785,11 @@ status_t AaptDir::validate() const
size_t j;
for (j = i+1; j < ND; j++) {
- if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
- mDirs.valueAt(j)->getLeaf().string()) == 0) {
+ if (strcasecmp(mDirs.valueAt(i)->getLeaf().c_str(),
+ mDirs.valueAt(j)->getLeaf().c_str()) == 0) {
SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
"Directory is case-insensitive equivalent to: %s",
- mDirs.valueAt(j)->getPrintableSource().string());
+ mDirs.valueAt(j)->getPrintableSource().c_str());
return UNKNOWN_ERROR;
}
}
@@ -846,12 +846,12 @@ status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
ssize_t pos = mSymbols.indexOfKey(name);
if (pos < 0) {
- entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
+ entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.c_str());
err = UNKNOWN_ERROR;
continue;
}
//printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
- // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
+ // i, N, name.c_str(), entry.isJavaSymbol ? 1 : 0);
mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
}
@@ -862,11 +862,11 @@ status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
ssize_t pos = mNestedSymbols.indexOfKey(name);
if (pos < 0) {
SourcePos pos;
- pos.error("Java symbol dir %s not defined\n", name.string());
+ pos.error("Java symbol dir %s not defined\n", name.c_str());
err = UNKNOWN_ERROR;
continue;
}
- //printf("**** applying java symbols in dir %s\n", name.string());
+ //printf("**** applying java symbols in dir %s\n", name.c_str());
status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
if (myerr != NO_ERROR) {
err = myerr;
@@ -1131,9 +1131,9 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
{
ssize_t err = 0;
- DIR* dir = opendir(srcDir.string());
+ DIR* dir = opendir(srcDir.c_str());
if (dir == NULL) {
- fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
+ fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.c_str(), strerror(errno));
return UNKNOWN_ERROR;
}
@@ -1149,7 +1149,7 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
break;
}
- if (isHidden(srcDir.string(), entry->d_name)) {
+ if (isHidden(srcDir.c_str(), entry->d_name)) {
continue;
}
@@ -1160,7 +1160,7 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
String8 resType;
bool b = group.initFromDirName(entry->d_name, &resType);
if (!b) {
- fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.string(),
+ fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.c_str(),
entry->d_name);
err = -1;
continue;
@@ -1168,7 +1168,7 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
int maxResInt = atoi(bundle->getMaxResVersion());
- const char *verString = group.getVersionString().string();
+ const char *verString = group.getVersionString().c_str();
int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
if (dirVersionInt > maxResInt) {
fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
@@ -1176,7 +1176,7 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
}
}
- FileType type = getFileType(subdirName.string());
+ FileType type = getFileType(subdirName.c_str());
if (type == kFileTypeDirectory) {
sp<AaptDir> dir = makeDir(resType);
@@ -1200,7 +1200,7 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
}
} else {
if (bundle->getVerbose()) {
- fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
+ fprintf(stderr, " (ignoring file '%s')\n", subdirName.c_str());
}
}
}
@@ -1248,7 +1248,7 @@ AaptAssets::slurpResourceZip(Bundle* /* bundle */, const char* filename)
String8 remain;
if (entryName.walkPath(&remain) == kResourceDir) {
// these are the resources, pull their type out of the directory name
- kind.initFromDirName(remain.walkPath().string(), &resType);
+ kind.initFromDirName(remain.walkPath().c_str(), &resType);
} else {
// these are untyped and don't have an AaptGroupEntry
}
@@ -1263,7 +1263,7 @@ AaptAssets::slurpResourceZip(Bundle* /* bundle */, const char* filename)
sp<AaptFile> file = new AaptFile(entryName, kind, resType);
status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
if (err != NO_ERROR) {
- fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
+ fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.c_str());
count = err;
goto bail;
}
@@ -1273,7 +1273,7 @@ AaptAssets::slurpResourceZip(Bundle* /* bundle */, const char* filename)
if (entryName == "AndroidManifest.xml") {
printf("AndroidManifest.xml\n");
}
- printf("\n\nfile: %s\n", entryName.string());
+ printf("\n\nfile: %s\n", entryName.c_str());
#endif
size_t len = entry->getUncompressedLen();
@@ -1317,9 +1317,9 @@ status_t AaptAssets::filter(Bundle* bundle)
uint32_t preferredDensity = 0;
if (bundle->getPreferredDensity().size() > 0) {
ResTable_config preferredConfig;
- if (!AaptConfig::parseDensity(bundle->getPreferredDensity().string(), &preferredConfig)) {
+ if (!AaptConfig::parseDensity(bundle->getPreferredDensity().c_str(), &preferredConfig)) {
fprintf(stderr, "Error parsing preferred density: %s\n",
- bundle->getPreferredDensity().string());
+ bundle->getPreferredDensity().c_str());
return UNKNOWN_ERROR;
}
preferredDensity = preferredConfig.density;
@@ -1332,11 +1332,11 @@ status_t AaptAssets::filter(Bundle* bundle)
if (bundle->getVerbose()) {
if (!reqFilter->isEmpty()) {
printf("Applying required filter: %s\n",
- bundle->getConfigurations().string());
+ bundle->getConfigurations().c_str());
}
if (preferredDensity > 0) {
printf("Applying preferred density filter: %s\n",
- bundle->getPreferredDensity().string());
+ bundle->getPreferredDensity().c_str());
}
}
@@ -1385,7 +1385,7 @@ status_t AaptAssets::filter(Bundle* bundle)
if (!reqFilter->match(config)) {
if (bundle->getVerbose()) {
printf("Pruning unneeded resource: %s\n",
- file->getPrintableSource().string());
+ file->getPrintableSource().c_str());
}
grp->removeFile(k);
k--;
@@ -1453,7 +1453,7 @@ status_t AaptAssets::filter(Bundle* bundle)
if (bestDensity != config.density) {
if (bundle->getVerbose()) {
printf("Pruning unneeded resource: %s\n",
- file->getPrintableSource().string());
+ file->getPrintableSource().c_str());
}
grp->removeFile(k);
k--;
@@ -1495,10 +1495,10 @@ status_t AaptAssets::applyJavaSymbols()
ssize_t pos = mSymbols.indexOfKey(name);
if (pos < 0) {
SourcePos pos;
- pos.error("Java symbol dir %s not defined\n", name.string());
+ pos.error("Java symbol dir %s not defined\n", name.c_str());
return UNKNOWN_ERROR;
}
- //printf("**** applying java symbols in dir %s\n", name.string());
+ //printf("**** applying java symbols in dir %s\n", name.c_str());
status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
if (err != NO_ERROR) {
return err;
@@ -1510,7 +1510,7 @@ status_t AaptAssets::applyJavaSymbols()
bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
//printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
- // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
+ // sym.name.c_str(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
// sym.isJavaSymbol ? 1 : 0);
if (!mHavePrivateSymbols) return true;
if (sym.isPublic) return true;
@@ -1529,12 +1529,12 @@ status_t AaptAssets::buildIncludedResources(Bundle* bundle)
const size_t packageIncludeCount = includes.size();
for (size_t i = 0; i < packageIncludeCount; i++) {
if (bundle->getVerbose()) {
- printf("Including resources from package: %s\n", includes[i].string());
+ printf("Including resources from package: %s\n", includes[i].c_str());
}
if (!mIncludedAssets.addAssetPath(includes[i], NULL)) {
fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
- includes[i].string());
+ includes[i].c_str());
return UNKNOWN_ERROR;
}
}
@@ -1543,12 +1543,12 @@ status_t AaptAssets::buildIncludedResources(Bundle* bundle)
if (!featureOfBase.isEmpty()) {
if (bundle->getVerbose()) {
printf("Including base feature resources from package: %s\n",
- featureOfBase.string());
+ featureOfBase.c_str());
}
if (!mIncludedAssets.addAssetPath(featureOfBase, NULL)) {
fprintf(stderr, "ERROR: base feature package '%s' not found.\n",
- featureOfBase.string());
+ featureOfBase.c_str());
return UNKNOWN_ERROR;
}
}
@@ -1581,23 +1581,23 @@ void AaptAssets::print(const String8& prefix) const
innerPrefix.append(" ");
String8 innerInnerPrefix(innerPrefix);
innerInnerPrefix.append(" ");
- printf("%sConfigurations:\n", prefix.string());
+ printf("%sConfigurations:\n", prefix.c_str());
const size_t N=mGroupEntries.size();
for (size_t i=0; i<N; i++) {
String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
- printf("%s %s\n", prefix.string(),
- cname != "" ? cname.string() : "(default)");
+ printf("%s %s\n", prefix.c_str(),
+ cname != "" ? cname.c_str() : "(default)");
}
- printf("\n%sFiles:\n", prefix.string());
+ printf("\n%sFiles:\n", prefix.c_str());
AaptDir::print(innerPrefix);
- printf("\n%sResource Dirs:\n", prefix.string());
+ printf("\n%sResource Dirs:\n", prefix.c_str());
const Vector<sp<AaptDir> >& resdirs = mResDirs;
const size_t NR = resdirs.size();
for (size_t i=0; i<NR; i++) {
const sp<AaptDir>& d = resdirs.itemAt(i);
- printf("%s Type %s\n", prefix.string(), d->getLeaf().string());
+ printf("%s Type %s\n", prefix.c_str(), d->getLeaf().c_str());
d->print(innerInnerPrefix);
}
}
@@ -1631,7 +1631,7 @@ valid_symbol_name(const String8& symbol)
NULL
};
const char*const* k = KEYWORDS;
- const char*const s = symbol.string();
+ const char*const s = symbol.c_str();
while (*k) {
if (0 == strcmp(s, *k)) {
return false;
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index eadd48a6c261..498fc4e38c8c 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -463,7 +463,7 @@ private:
if (valid_symbol_name(symbol)) {
return true;
}
- pos.error("invalid %s: '%s'\n", label, symbol.string());
+ pos.error("invalid %s: '%s'\n", label, symbol.c_str());
return false;
}
AaptSymbolEntry& edit_symbol(const String8& symbol, const SourcePos* pos) {
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index 0aca45ea8d60..7578f79f792e 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -39,7 +39,7 @@ bool parse(const String8& str, ConfigDescription* out) {
ssize_t index = 0;
ssize_t localeIndex = 0;
const ssize_t N = parts.size();
- const char* part = parts[index].string();
+ const char* part = parts[index].c_str();
if (str.length() == 0) {
goto success;
@@ -50,7 +50,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseMnc(part, &config)) {
@@ -58,7 +58,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
// Locale spans a few '-' separators, so we let it
@@ -72,7 +72,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index >= N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseLayoutDirection(part, &config)) {
@@ -80,7 +80,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseSmallestScreenWidthDp(part, &config)) {
@@ -88,7 +88,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseScreenWidthDp(part, &config)) {
@@ -96,7 +96,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseScreenHeightDp(part, &config)) {
@@ -104,7 +104,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseScreenLayoutSize(part, &config)) {
@@ -112,7 +112,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseScreenLayoutLong(part, &config)) {
@@ -120,7 +120,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseScreenRound(part, &config)) {
@@ -128,7 +128,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseWideColorGamut(part, &config)) {
@@ -136,7 +136,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseHdr(part, &config)) {
@@ -144,7 +144,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseOrientation(part, &config)) {
@@ -152,7 +152,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseUiModeType(part, &config)) {
@@ -160,7 +160,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseUiModeNight(part, &config)) {
@@ -168,7 +168,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseDensity(part, &config)) {
@@ -176,7 +176,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseTouchscreen(part, &config)) {
@@ -184,7 +184,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseKeysHidden(part, &config)) {
@@ -192,7 +192,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseKeyboard(part, &config)) {
@@ -200,7 +200,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseNavHidden(part, &config)) {
@@ -208,7 +208,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseNavigation(part, &config)) {
@@ -216,7 +216,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseScreenSize(part, &config)) {
@@ -224,7 +224,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
if (parseVersion(part, &config)) {
@@ -232,7 +232,7 @@ bool parse(const String8& str, ConfigDescription* out) {
if (index == N) {
goto success;
}
- part = parts[index].string();
+ part = parts[index].c_str();
}
// Unrecognized.
@@ -773,8 +773,8 @@ bool parseScreenSize(const char* name, ResTable_config* out) {
if (y == name || *y != 0) return false;
String8 yName(x, y-x);
- uint16_t w = (uint16_t)atoi(xName.string());
- uint16_t h = (uint16_t)atoi(yName.string());
+ uint16_t w = (uint16_t)atoi(xName.c_str());
+ uint16_t h = (uint16_t)atoi(yName.c_str());
if (w < h) {
return false;
}
@@ -805,7 +805,7 @@ bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
String8 xName(name, x-name);
if (out) {
- out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
+ out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
}
return true;
@@ -827,7 +827,7 @@ bool parseScreenWidthDp(const char* name, ResTable_config* out) {
String8 xName(name, x-name);
if (out) {
- out->screenWidthDp = (uint16_t)atoi(xName.string());
+ out->screenWidthDp = (uint16_t)atoi(xName.c_str());
}
return true;
@@ -849,7 +849,7 @@ bool parseScreenHeightDp(const char* name, ResTable_config* out) {
String8 xName(name, x-name);
if (out) {
- out->screenHeightDp = (uint16_t)atoi(xName.string());
+ out->screenHeightDp = (uint16_t)atoi(xName.c_str());
}
return true;
@@ -875,7 +875,7 @@ bool parseVersion(const char* name, ResTable_config* out) {
String8 sdkName(name, s-name);
if (out) {
- out->sdkVersion = (uint16_t)atoi(sdkName.string());
+ out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
out->minorVersion = 0;
}
diff --git a/tools/aapt/AaptUtil.cpp b/tools/aapt/AaptUtil.cpp
index 293e144b71fe..e82860de578a 100644
--- a/tools/aapt/AaptUtil.cpp
+++ b/tools/aapt/AaptUtil.cpp
@@ -23,7 +23,7 @@ namespace AaptUtil {
Vector<String8> split(const String8& str, const char sep) {
Vector<String8> parts;
- const char* p = str.string();
+ const char* p = str.c_str();
const char* q;
while (true) {
@@ -41,7 +41,7 @@ Vector<String8> split(const String8& str, const char sep) {
Vector<String8> splitAndLowerCase(const String8& str, const char sep) {
Vector<String8> parts;
- const char* p = str.string();
+ const char* p = str.c_str();
const char* q;
while (true) {
diff --git a/tools/aapt/ApkBuilder.cpp b/tools/aapt/ApkBuilder.cpp
index 01e02e270b63..335c43b96599 100644
--- a/tools/aapt/ApkBuilder.cpp
+++ b/tools/aapt/ApkBuilder.cpp
@@ -36,7 +36,7 @@ status_t ApkBuilder::createSplitForConfigs(const std::set<ConfigDescription>& co
if (splitConfigs.count(*iter) > 0) {
// Can't have overlapping configurations.
fprintf(stderr, "ERROR: Split configuration '%s' is already defined "
- "in another split.\n", iter->toString().string());
+ "in another split.\n", iter->toString().c_str());
return ALREADY_EXISTS;
}
}
@@ -115,10 +115,10 @@ status_t ApkSplit::addEntry(const String8& path, const sp<AaptFile>& file) {
}
void ApkSplit::print() const {
- fprintf(stderr, "APK Split '%s'\n", mName.string());
+ fprintf(stderr, "APK Split '%s'\n", mName.c_str());
std::set<OutputEntry>::const_iterator iter = mFiles.begin();
for (; iter != mFiles.end(); iter++) {
- fprintf(stderr, " %s (%s)\n", iter->getPath().string(), iter->getFile()->getSourceFile().string());
+ fprintf(stderr, " %s (%s)\n", iter->getPath().c_str(), iter->getFile()->getSourceFile().c_str());
}
}
diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h
index 6fa96d67e6a3..2dc143c6a66d 100644
--- a/tools/aapt/CacheUpdater.h
+++ b/tools/aapt/CacheUpdater.h
@@ -66,7 +66,7 @@ public:
// Check optomistically to see if all directories exist.
// If something in the path doesn't exist, then walk the path backwards
// and find the place to start creating directories forward.
- if (stat(path.string(),&s) == -1) {
+ if (stat(path.c_str(),&s) == -1) {
// Walk backwards to find place to start creating directories
existsPath = path;
do {
@@ -74,7 +74,7 @@ public:
// the string of paths to create.
toCreate = existsPath.getPathLeaf().appendPath(toCreate);
existsPath = existsPath.getPathDir();
- } while (stat(existsPath.string(),&s) == -1);
+ } while (stat(existsPath.c_str(),&s) == -1);
// Walk forwards and build directories as we go
do {
@@ -82,9 +82,9 @@ public:
existsPath.appendPath(toCreate.walkPath(&remains));
toCreate = remains;
#ifdef _WIN32
- _mkdir(existsPath.string());
+ _mkdir(existsPath.c_str());
#else
- mkdir(existsPath.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+ mkdir(existsPath.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
#endif
} while (remains.length() > 0);
} //if
@@ -93,8 +93,8 @@ public:
// Delete a file
virtual void deleteFile(String8 path)
{
- if (remove(path.string()) != 0)
- fprintf(stderr,"ERROR DELETING %s\n",path.string());
+ if (remove(path.c_str()) != 0)
+ fprintf(stderr,"ERROR DELETING %s\n",path.c_str());
};
// Process an image from source out to dest
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 51cf38bce64e..5a06b102592a 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -240,13 +240,13 @@ static void printResolvedResourceAttribute(const ResTable& resTable, const ResXM
}
if (value.dataType == Res_value::TYPE_STRING) {
String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
- printf("%s='%s'", attrLabel.string(),
- ResTable::normalizeForOutput(result.string()).string());
+ printf("%s='%s'", attrLabel.c_str(),
+ ResTable::normalizeForOutput(result.c_str()).c_str());
} else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
value.dataType <= Res_value::TYPE_LAST_INT) {
- printf("%s='%d'", attrLabel.string(), value.data);
+ printf("%s='%d'", attrLabel.c_str(), value.data);
} else {
- printf("%s='0x%x'", attrLabel.string(), (int)value.data);
+ printf("%s='0x%x'", attrLabel.c_str(), (int)value.data);
}
}
@@ -355,21 +355,21 @@ static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
const String8& requiredFeature = String8(),
const String8& requiredNotFeature = String8()) {
- printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
+ printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.c_str()).c_str());
if (maxSdkVersion != -1) {
printf(" maxSdkVersion='%d'", maxSdkVersion);
}
if (requiredFeature.length() > 0) {
- printf(" requiredFeature='%s'", requiredFeature.string());
+ printf(" requiredFeature='%s'", requiredFeature.c_str());
}
if (requiredNotFeature.length() > 0) {
- printf(" requiredNotFeature='%s'", requiredNotFeature.string());
+ printf(" requiredNotFeature='%s'", requiredNotFeature.c_str());
}
printf("\n");
if (optional) {
printf("optional-permission: name='%s'",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
if (maxSdkVersion != -1) {
printf(" maxSdkVersion='%d'", maxSdkVersion);
}
@@ -380,7 +380,7 @@ static void printUsesPermission(const String8& name, bool optional=false, int ma
static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
printf("uses-permission-sdk-23: ");
- printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
+ printf("name='%s'", ResTable::normalizeForOutput(name.c_str()).c_str());
if (maxSdkVersion != -1) {
printf(" maxSdkVersion='%d'", maxSdkVersion);
}
@@ -390,11 +390,11 @@ static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1)
static void printUsesImpliedPermission(const String8& name, const String8& reason,
const int32_t maxSdkVersion = -1) {
printf("uses-implied-permission: name='%s'",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
if (maxSdkVersion != -1) {
printf(" maxSdkVersion='%d'", maxSdkVersion);
}
- printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.string()).string());
+ printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.c_str()).c_str());
}
Vector<String8> getNfcAidCategories(AssetManager& assets, const String8& xmlPath, bool offHost,
@@ -556,7 +556,7 @@ static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatu
static void printFeatureGroupImpl(const FeatureGroup& grp,
const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
- printf("feature-group: label='%s'\n", grp.label.string());
+ printf("feature-group: label='%s'\n", grp.label.c_str());
if (grp.openGLESVersion > 0) {
printf(" uses-gl-es: '0x%x'\n", grp.openGLESVersion);
@@ -570,7 +570,7 @@ static void printFeatureGroupImpl(const FeatureGroup& grp,
const String8& featureName = grp.features.keyAt(i);
printf(" uses-feature%s: name='%s'", (required ? "" : "-not-required"),
- ResTable::normalizeForOutput(featureName.string()).string());
+ ResTable::normalizeForOutput(featureName.c_str()).c_str());
if (version > 0) {
printf(" version='%d'", version);
@@ -589,15 +589,15 @@ static void printFeatureGroupImpl(const FeatureGroup& grp,
}
String8 printableFeatureName(ResTable::normalizeForOutput(
- impliedFeature.name.string()));
+ impliedFeature.name.c_str()));
const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
- printf(" uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
+ printf(" uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.c_str());
printf(" uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
- printableFeatureName.string());
+ printableFeatureName.c_str());
const size_t numReasons = impliedFeature.reasons.size();
for (size_t j = 0; j < numReasons; j++) {
- printf("%s", impliedFeature.reasons[j].string());
+ printf("%s", impliedFeature.reasons[j].c_str());
if (j + 2 < numReasons) {
printf(", ");
} else if (j + 1 < numReasons) {
@@ -649,43 +649,43 @@ static void addImpliedFeaturesForPermission(const int targetSdk, const String8&
bool impliedBySdk23Permission) {
if (name == "android.permission.CAMERA") {
addImpliedFeature(impliedFeatures, "android.hardware.camera",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
} else if (name == "android.permission.ACCESS_FINE_LOCATION") {
if (targetSdk < SDK_LOLLIPOP) {
addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
impliedBySdk23Permission);
}
addImpliedFeature(impliedFeatures, "android.hardware.location",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
} else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
if (targetSdk < SDK_LOLLIPOP) {
addImpliedFeature(impliedFeatures, "android.hardware.location.network",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
addImpliedFeature(impliedFeatures, "android.hardware.location.network",
String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
impliedBySdk23Permission);
}
addImpliedFeature(impliedFeatures, "android.hardware.location",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
} else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
name == "android.permission.INSTALL_LOCATION_PROVIDER") {
addImpliedFeature(impliedFeatures, "android.hardware.location",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
} else if (name == "android.permission.BLUETOOTH" ||
name == "android.permission.BLUETOOTH_ADMIN") {
if (targetSdk > SDK_DONUT) {
addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
String8::format("targetSdkVersion > %d", SDK_DONUT),
@@ -693,13 +693,13 @@ static void addImpliedFeaturesForPermission(const int targetSdk, const String8&
}
} else if (name == "android.permission.RECORD_AUDIO") {
addImpliedFeature(impliedFeatures, "android.hardware.microphone",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
} else if (name == "android.permission.ACCESS_WIFI_STATE" ||
name == "android.permission.CHANGE_WIFI_STATE" ||
name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
addImpliedFeature(impliedFeatures, "android.hardware.wifi",
- String8::format("requested %s permission", name.string()),
+ String8::format("requested %s permission", name.c_str()),
impliedBySdk23Permission);
} else if (name == "android.permission.CALL_PHONE" ||
name == "android.permission.CALL_PRIVILEGED" ||
@@ -746,7 +746,7 @@ int doDump(Bundle* bundle)
for (size_t i = 0; i < bundle->getPackageIncludes().size(); i++) {
const String8& assetPath = bundle->getPackageIncludes()[i];
if (!assets.addAssetPath(assetPath, NULL)) {
- fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.string());
+ fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.c_str());
return 1;
}
}
@@ -890,7 +890,7 @@ int doDump(Bundle* bundle)
goto bail;
}
String8 tag(ctag16);
- //printf("Depth %d tag %s\n", depth, tag.string());
+ //printf("Depth %d tag %s\n", depth, tag.c_str());
if (depth == 1) {
if (tag != "manifest") {
SourcePos(manifestFile, tree.getLineNumber()).error(
@@ -898,14 +898,14 @@ int doDump(Bundle* bundle)
goto bail;
}
String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
- printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
+ printf("package: %s\n", ResTable::normalizeForOutput(pkg.c_str()).c_str());
} else if (depth == 2) {
if (tag == "permission") {
String8 error;
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name': %s", error.string());
+ "ERROR getting 'android:name': %s", error.c_str());
goto bail;
}
@@ -915,13 +915,13 @@ int doDump(Bundle* bundle)
goto bail;
}
printf("permission: %s\n",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
} else if (tag == "uses-permission") {
String8 error;
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
@@ -938,7 +938,7 @@ int doDump(Bundle* bundle)
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
@@ -1138,7 +1138,7 @@ int doDump(Bundle* bundle)
const size_t N = supportedInput.size();
for (size_t i=0; i<N; i++) {
printf("%s", ResTable::normalizeForOutput(
- supportedInput[i].string()).string());
+ supportedInput[i].c_str()).c_str());
if (i != N - 1) {
printf("' '");
} else {
@@ -1157,27 +1157,27 @@ int doDump(Bundle* bundle)
printf("launchable-activity:");
if (aName.length() > 0) {
printf(" name='%s' ",
- ResTable::normalizeForOutput(aName.string()).string());
+ ResTable::normalizeForOutput(aName.c_str()).c_str());
}
printf(" label='%s' icon='%s'\n",
- ResTable::normalizeForOutput(activityLabel.string())
- .string(),
- ResTable::normalizeForOutput(activityIcon.string())
- .string());
+ ResTable::normalizeForOutput(activityLabel.c_str())
+ .c_str(),
+ ResTable::normalizeForOutput(activityIcon.c_str())
+ .c_str());
}
if (isLeanbackLauncherActivity) {
printf("leanback-launchable-activity:");
if (aName.length() > 0) {
printf(" name='%s' ",
- ResTable::normalizeForOutput(aName.string()).string());
+ ResTable::normalizeForOutput(aName.c_str()).c_str());
}
printf(" label='%s' icon='%s' banner='%s'\n",
- ResTable::normalizeForOutput(activityLabel.string())
- .string(),
- ResTable::normalizeForOutput(activityIcon.string())
- .string(),
- ResTable::normalizeForOutput(activityBanner.string())
- .string());
+ ResTable::normalizeForOutput(activityLabel.c_str())
+ .c_str(),
+ ResTable::normalizeForOutput(activityIcon.c_str())
+ .c_str(),
+ ResTable::normalizeForOutput(activityBanner.c_str())
+ .c_str());
}
}
if (!hasIntentFilter) {
@@ -1265,7 +1265,7 @@ int doDump(Bundle* bundle)
goto bail;
}
String8 tag(ctag16);
- //printf("Depth %d, %s\n", depth, tag.string());
+ //printf("Depth %d, %s\n", depth, tag.c_str());
if (depth == 1) {
if (tag != "manifest") {
SourcePos(manifestFile, tree.getLineNumber()).error(
@@ -1274,13 +1274,13 @@ int doDump(Bundle* bundle)
}
pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
printf("package: name='%s' ",
- ResTable::normalizeForOutput(pkg.string()).string());
+ ResTable::normalizeForOutput(pkg.c_str()).c_str());
int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
&error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:versionCode' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
if (versionCode > 0) {
@@ -1293,16 +1293,16 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:versionName' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
printf("versionName='%s'",
- ResTable::normalizeForOutput(versionName.string()).string());
+ ResTable::normalizeForOutput(versionName.c_str()).c_str());
String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
if (!splitName.isEmpty()) {
printf(" split='%s'", ResTable::normalizeForOutput(
- splitName.string()).string());
+ splitName.c_str()).c_str());
}
// For 'platformBuildVersionName', using both string and int type as a fallback
@@ -1313,7 +1313,7 @@ int doDump(Bundle* bundle)
AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionName", 0,
NULL);
if (platformBuildVersionName != "") {
- printf(" platformBuildVersionName='%s'", platformBuildVersionName.string());
+ printf(" platformBuildVersionName='%s'", platformBuildVersionName.c_str());
} else if (platformBuildVersionNameInt > 0) {
printf(" platformBuildVersionName='%d'", platformBuildVersionNameInt);
}
@@ -1326,7 +1326,7 @@ int doDump(Bundle* bundle)
AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionCode", 0,
NULL);
if (platformBuildVersionCode != "") {
- printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.string());
+ printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.c_str());
} else if (platformBuildVersionCodeInt > 0) {
printf(" platformBuildVersionCode='%d'", platformBuildVersionCodeInt);
}
@@ -1336,7 +1336,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:compileSdkVersion' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
if (compileSdkVersion > 0) {
@@ -1347,7 +1347,7 @@ int doDump(Bundle* bundle)
COMPILE_SDK_VERSION_CODENAME_ATTR, &error);
if (compileSdkVersionCodename != "") {
printf(" compileSdkVersionCodename='%s'", ResTable::normalizeForOutput(
- compileSdkVersionCodename.string()).string());
+ compileSdkVersionCodename.c_str()).c_str());
}
printf("\n");
@@ -1357,7 +1357,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:installLocation' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1387,7 +1387,7 @@ int doDump(Bundle* bundle)
String8 label;
const size_t NL = locales.size();
for (size_t i=0; i<NL; i++) {
- const char* localeStr = locales[i].string();
+ const char* localeStr = locales[i].c_str();
assets.setConfiguration(config, localeStr != NULL ? localeStr : "");
String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
&error);
@@ -1395,13 +1395,13 @@ int doDump(Bundle* bundle)
if (localeStr == NULL || strlen(localeStr) == 0) {
label = llabel;
printf("application-label:'%s'\n",
- ResTable::normalizeForOutput(llabel.string()).string());
+ ResTable::normalizeForOutput(llabel.c_str()).c_str());
} else {
if (label == "") {
label = llabel;
}
printf("application-label-%s:'%s'\n", localeStr,
- ResTable::normalizeForOutput(llabel.string()).string());
+ ResTable::normalizeForOutput(llabel.c_str()).c_str());
}
}
}
@@ -1415,7 +1415,7 @@ int doDump(Bundle* bundle)
&error);
if (icon != "") {
printf("application-icon-%d:'%s'\n", densities[i],
- ResTable::normalizeForOutput(icon.string()).string());
+ ResTable::normalizeForOutput(icon.c_str()).c_str());
}
}
assets.setConfiguration(config);
@@ -1423,7 +1423,7 @@ int doDump(Bundle* bundle)
String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:icon' attribute: %s", error.string());
+ "ERROR getting 'android:icon' attribute: %s", error.c_str());
goto bail;
}
int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
@@ -1431,7 +1431,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:testOnly' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1439,15 +1439,15 @@ int doDump(Bundle* bundle)
&error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:banner' attribute: %s", error.string());
+ "ERROR getting 'android:banner' attribute: %s", error.c_str());
goto bail;
}
printf("application: label='%s' ",
- ResTable::normalizeForOutput(label.string()).string());
- printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
+ ResTable::normalizeForOutput(label.c_str()).c_str());
+ printf("icon='%s'", ResTable::normalizeForOutput(icon.c_str()).c_str());
if (banner != "") {
printf(" banner='%s'",
- ResTable::normalizeForOutput(banner.string()).string());
+ ResTable::normalizeForOutput(banner.c_str()).c_str());
}
printf("\n");
if (testOnly != 0) {
@@ -1458,7 +1458,7 @@ int doDump(Bundle* bundle)
ISGAME_ATTR, 0, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:isGame' attribute: %s", error.string());
+ "ERROR getting 'android:isGame' attribute: %s", error.c_str());
goto bail;
}
if (isGame != 0) {
@@ -1470,7 +1470,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:debuggable' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
if (debuggable != 0) {
@@ -1500,12 +1500,12 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:minSdkVersion' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
if (name == "Donut") targetSdk = SDK_DONUT;
printf("sdkVersion:'%s'\n",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
} else if (code != -1) {
targetSdk = code;
printf("sdkVersion:'%d'\n", code);
@@ -1522,7 +1522,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:targetSdkVersion' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
if (name == "Donut" && targetSdk < SDK_DONUT) {
@@ -1532,7 +1532,7 @@ int doDump(Bundle* bundle)
targetSdk = SDK_CUR_DEVELOPMENT;
}
printf("targetSdkVersion:'%s'\n",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
} else if (code != -1) {
if (targetSdk < code) {
targetSdk = code;
@@ -1592,7 +1592,7 @@ int doDump(Bundle* bundle)
group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:label' attribute: %s", error.string());
+ "ERROR getting 'android:label' attribute: %s", error.c_str());
goto bail;
}
featureGroups.add(group);
@@ -1608,7 +1608,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"failed to read attribute 'android:required': %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1617,7 +1617,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"failed to read attribute 'android:version': %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1638,7 +1638,7 @@ int doDump(Bundle* bundle)
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
@@ -1682,7 +1682,7 @@ int doDump(Bundle* bundle)
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
@@ -1701,37 +1701,37 @@ int doDump(Bundle* bundle)
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
printf("uses-package:'%s'\n",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
} else {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
} else if (tag == "original-package") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
printf("original-package:'%s'\n",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
} else {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
} else if (tag == "supports-gl-texture") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
printf("supports-gl-texture:'%s'\n",
- ResTable::normalizeForOutput(name.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str());
} else {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
} else if (tag == "compatible-screens") {
printCompatibleScreens(tree, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting compatible screens: %s", error.string());
+ "ERROR getting compatible screens: %s", error.c_str());
goto bail;
}
depth--;
@@ -1742,8 +1742,8 @@ int doDump(Bundle* bundle)
&error);
if (publicKey != "" && error == "") {
printf("package-verifier: name='%s' publicKey='%s'\n",
- ResTable::normalizeForOutput(name.string()).string(),
- ResTable::normalizeForOutput(publicKey.string()).string());
+ ResTable::normalizeForOutput(name.c_str()).c_str(),
+ ResTable::normalizeForOutput(publicKey.c_str()).c_str());
}
}
}
@@ -1769,7 +1769,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1778,7 +1778,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:label' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1787,7 +1787,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:icon' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1796,7 +1796,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:banner' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -1824,14 +1824,14 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute for uses-library"
- " %s", error.string());
+ " %s", error.c_str());
goto bail;
}
int req = AaptXml::getIntegerAttribute(tree,
REQUIRED_ATTR, 1);
printf("uses-library%s:'%s'\n",
req ? "" : "-not-required", ResTable::normalizeForOutput(
- libraryName.string()).string());
+ libraryName.c_str()).c_str());
} else if (tag == "receiver") {
withinReceiver = true;
receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
@@ -1839,7 +1839,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute for receiver:"
- " %s", error.string());
+ " %s", error.c_str());
goto bail;
}
@@ -1853,7 +1853,7 @@ int doDump(Bundle* bundle)
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:permission' attribute for"
" receiver '%s': %s",
- receiverName.string(), error.string());
+ receiverName.c_str(), error.c_str());
}
} else if (tag == "service") {
withinService = true;
@@ -1862,7 +1862,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute for "
- "service:%s", error.string());
+ "service:%s", error.c_str());
goto bail;
}
@@ -1887,7 +1887,7 @@ int doDump(Bundle* bundle)
} else {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:permission' attribute for "
- "service '%s': %s", serviceName.string(), error.string());
+ "service '%s': %s", serviceName.c_str(), error.c_str());
}
} else if (tag == "provider") {
withinProvider = true;
@@ -1897,7 +1897,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:exported' attribute for provider:"
- " %s", error.string());
+ " %s", error.c_str());
goto bail;
}
@@ -1906,7 +1906,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:grantUriPermissions' attribute for "
- "provider: %s", error.string());
+ "provider: %s", error.c_str());
goto bail;
}
@@ -1915,7 +1915,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:permission' attribute for "
- "provider: %s", error.string());
+ "provider: %s", error.c_str());
goto bail;
}
@@ -1928,11 +1928,11 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute for "
- "meta-data: %s", error.string());
+ "meta-data: %s", error.c_str());
goto bail;
}
printf("meta-data: name='%s' ",
- ResTable::normalizeForOutput(metaDataName.string()).string());
+ ResTable::normalizeForOutput(metaDataName.c_str()).c_str());
printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"),
&error);
if (error != "") {
@@ -1944,7 +1944,7 @@ int doDump(Bundle* bundle)
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:value' or "
"'android:resource' attribute for "
- "meta-data: %s", error.string());
+ "meta-data: %s", error.c_str());
goto bail;
}
}
@@ -1956,7 +1956,7 @@ int doDump(Bundle* bundle)
} else {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute: %s",
- error.string());
+ error.c_str());
goto bail;
}
}
@@ -1969,13 +1969,13 @@ int doDump(Bundle* bundle)
Feature feature(true);
int32_t featureVers = AaptXml::getIntegerAttribute(
- tree, androidSchema.string(), "version", 0, &error);
+ tree, androidSchema.c_str(), "version", 0, &error);
if (error == "") {
feature.version = featureVers;
} else {
SourcePos(manifestFile, tree.getLineNumber()).error(
"failed to read attribute 'android:version': %s",
- error.string());
+ error.c_str());
goto bail;
}
@@ -2016,8 +2016,8 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:name' attribute for "
- "meta-data tag in service '%s': %s", serviceName.string(),
- error.string());
+ "meta-data tag in service '%s': %s", serviceName.c_str(),
+ error.c_str());
goto bail;
}
@@ -2034,7 +2034,7 @@ int doDump(Bundle* bundle)
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:resource' attribute for "
"meta-data tag in service '%s': %s",
- serviceName.string(), error.string());
+ serviceName.c_str(), error.c_str());
goto bail;
}
@@ -2043,7 +2043,7 @@ int doDump(Bundle* bundle)
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting AID category for service '%s'",
- serviceName.string());
+ serviceName.c_str());
goto bail;
}
@@ -2064,7 +2064,7 @@ int doDump(Bundle* bundle)
action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'android:name' attribute: %s", error.string());
+ "ERROR getting 'android:name' attribute: %s", error.c_str());
goto bail;
}
@@ -2120,7 +2120,7 @@ int doDump(Bundle* bundle)
String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
- "ERROR getting 'name' attribute: %s", error.string());
+ "ERROR getting 'name' attribute: %s", error.c_str());
goto bail;
}
if (withinActivity) {
@@ -2352,7 +2352,7 @@ int doDump(Bundle* bundle)
printf("locales:");
const size_t NL = locales.size();
for (size_t i=0; i<NL; i++) {
- const char* localeStr = locales[i].string();
+ const char* localeStr = locales[i].c_str();
if (localeStr == NULL || strlen(localeStr) == 0) {
localeStr = "--_--";
}
@@ -2373,7 +2373,7 @@ int doDump(Bundle* bundle)
SortedVector<String8> architectures;
for (size_t i=0; i<dir->getFileCount(); i++) {
architectures.add(ResTable::normalizeForOutput(
- dir->getFileName(i).string()));
+ dir->getFileName(i).c_str()));
}
bool outputAltNativeCode = false;
@@ -2401,7 +2401,7 @@ int doDump(Bundle* bundle)
}
if (index >= 0) {
- printf("native-code: '%s'\n", architectures[index].string());
+ printf("native-code: '%s'\n", architectures[index].c_str());
architectures.removeAt(index);
outputAltNativeCode = true;
}
@@ -2414,7 +2414,7 @@ int doDump(Bundle* bundle)
}
printf("native-code:");
for (size_t i = 0; i < archCount; i++) {
- printf(" '%s'", architectures[i].string());
+ printf(" '%s'", architectures[i].c_str());
}
printf("\n");
}
@@ -2428,7 +2428,7 @@ int doDump(Bundle* bundle)
res.getConfigurations(&configs);
const size_t N = configs.size();
for (size_t i=0; i<N; i++) {
- printf("%s\n", configs[i].toString().string());
+ printf("%s\n", configs[i].toString().c_str());
}
} else {
fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
@@ -2486,15 +2486,15 @@ int doAdd(Bundle* bundle)
for (int i = 1; i < bundle->getFileSpecCount(); i++) {
const char* fileName = bundle->getFileSpecEntry(i);
- if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
+ if (strcasecmp(String8(fileName).getPathExtension().c_str(), ".gz") == 0) {
printf(" '%s'... (from gzip)\n", fileName);
- result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
+ result = zip->addGzip(fileName, String8(fileName).getBasePath().c_str(), NULL);
} else {
if (bundle->getJunkPath()) {
String8 storageName = String8(fileName).getPathLeaf();
printf(" '%s' as '%s'...\n", fileName,
- ResTable::normalizeForOutput(storageName.string()).string());
- result = zip->add(fileName, storageName.string(),
+ ResTable::normalizeForOutput(storageName.c_str()).c_str());
+ result = zip->add(fileName, storageName.c_str(),
bundle->getCompressionMethod(), NULL);
} else {
printf(" '%s'...\n", fileName);
@@ -2581,7 +2581,7 @@ static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilde
for (size_t i = 0; i < numDirs; i++) {
bool ignore = ignoreConfig;
const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
- const char* dirStr = subDir->getLeaf().string();
+ const char* dirStr = subDir->getLeaf().c_str();
if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
ignore = true;
}
@@ -2604,7 +2604,7 @@ static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilde
}
if (err != NO_ERROR) {
fprintf(stderr, "Failed to add %s (%s) to builder.\n",
- gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
+ gp->getPath().c_str(), gp->getFiles()[j]->getPrintableSource().c_str());
return err;
}
}
@@ -2620,13 +2620,13 @@ static String8 buildApkName(const String8& original, const sp<ApkSplit>& split)
String8 ext(original.getPathExtension());
if (ext == String8(".apk")) {
return String8::format("%s_%s%s",
- original.getBasePath().string(),
- split->getDirectorySafeName().string(),
- ext.string());
+ original.getBasePath().c_str(),
+ split->getDirectorySafeName().c_str(),
+ ext.c_str());
}
- return String8::format("%s_%s", original.string(),
- split->getDirectorySafeName().string());
+ return String8::format("%s_%s", original.c_str(),
+ split->getDirectorySafeName().c_str());
}
/*
@@ -2712,7 +2712,7 @@ int doPackage(Bundle* bundle)
for (size_t i = 0; i < numSplits; i++) {
std::set<ConfigDescription> configs;
if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
- fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
+ fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].c_str());
goto bail;
}
@@ -2835,7 +2835,7 @@ int doPackage(Bundle* bundle)
String8 outputPath = buildApkName(String8(outputAPKFile), split);
err = writeAPK(bundle, outputPath, split);
if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
+ fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.c_str());
goto bail;
}
}
diff --git a/tools/aapt/CrunchCache.cpp b/tools/aapt/CrunchCache.cpp
index 7b8a576b88d3..1f2febec2230 100644
--- a/tools/aapt/CrunchCache.cpp
+++ b/tools/aapt/CrunchCache.cpp
@@ -44,7 +44,7 @@ size_t CrunchCache::crunch(CacheUpdater* cu, bool forceOverwrite)
// This efficiently strips the source directory prefix from our path.
// Also, String8 doesn't have a substring method so this is what we've
// got to work with.
- const char* rPathPtr = mSourceFiles.keyAt(0).string()+mSourcePath.length();
+ const char* rPathPtr = mSourceFiles.keyAt(0).c_str()+mSourcePath.length();
// Strip leading slash if present
int offset = 0;
if (rPathPtr[0] == OS_PATH_SEPARATOR)
diff --git a/tools/aapt/DirectoryWalker.h b/tools/aapt/DirectoryWalker.h
index 88031d04b2df..cea3a6eb0ecf 100644
--- a/tools/aapt/DirectoryWalker.h
+++ b/tools/aapt/DirectoryWalker.h
@@ -57,7 +57,7 @@ public:
virtual bool openDir(String8 path) {
mBasePath = path;
dir = NULL;
- dir = opendir(mBasePath.string() );
+ dir = opendir(mBasePath.c_str() );
if (dir == NULL)
return false;
@@ -78,7 +78,7 @@ public:
mEntry = *entryPtr;
// Get stats
String8 fullPath = mBasePath.appendPathCopy(mEntry.d_name);
- stat(fullPath.string(),&mStats);
+ stat(fullPath.c_str(),&mStats);
return &mEntry;
};
// Get the stats for the current entry
diff --git a/tools/aapt/FileFinder.cpp b/tools/aapt/FileFinder.cpp
index c9d0744a4463..a5c19806c804 100644
--- a/tools/aapt/FileFinder.cpp
+++ b/tools/aapt/FileFinder.cpp
@@ -59,14 +59,14 @@ bool SystemFileFinder::findFiles(String8 basePath, Vector<String8>& extensions,
String8 fullPath = basePath.appendPathCopy(entryName);
// If this entry is a directory we'll recurse into it
- if (isDirectory(fullPath.string()) ) {
+ if (isDirectory(fullPath.c_str()) ) {
DirectoryWalker* copy = dw->clone();
findFiles(fullPath, extensions, fileStore,copy);
delete copy;
}
// If this entry is a file, we'll pass it over to checkAndAddFile
- if (isFile(fullPath.string()) ) {
+ if (isFile(fullPath.c_str()) ) {
checkAndAddFile(fullPath,dw->entryStats(),extensions,fileStore);
}
}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 627a231de5c8..c6c7e960ba2a 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -1328,13 +1328,13 @@ static bool read_png_protected(png_structp read_ptr, String8& printableName, png
png_init_io(read_ptr, fp);
- read_png(printableName.string(), read_ptr, read_info, imageInfo);
+ read_png(printableName.c_str(), read_ptr, read_info, imageInfo);
const size_t nameLen = file->getPath().length();
if (nameLen > 6) {
- const char* name = file->getPath().string();
+ const char* name = file->getPath().c_str();
if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
- if (do_9patch(printableName.string(), imageInfo) != NO_ERROR) {
+ if (do_9patch(printableName.c_str(), imageInfo) != NO_ERROR) {
return false;
}
}
@@ -1349,7 +1349,7 @@ static bool write_png_protected(png_structp write_ptr, String8& printableName, p
return false;
}
- write_png(printableName.string(), write_ptr, write_info, *imageInfo, bundle);
+ write_png(printableName.c_str(), write_ptr, write_info, *imageInfo, bundle);
return true;
}
@@ -1360,7 +1360,7 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets *
String8 ext(file->getPath().getPathExtension());
// We currently only process PNG images.
- if (strcmp(ext.string(), ".png") != 0) {
+ if (strcmp(ext.c_str(), ".png") != 0) {
return NO_ERROR;
}
@@ -1371,7 +1371,7 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets *
String8 printableName(file->getPrintableSource());
if (bundle->getVerbose()) {
- printf("Processing image: %s\n", printableName.string());
+ printf("Processing image: %s\n", printableName.c_str());
}
png_structp read_ptr = NULL;
@@ -1385,9 +1385,9 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets *
status_t error = UNKNOWN_ERROR;
- fp = fopen(file->getSourceFile().string(), "rb");
+ fp = fopen(file->getSourceFile().c_str(), "rb");
if (fp == NULL) {
- fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.string());
+ fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.c_str());
goto bail;
}
@@ -1434,7 +1434,7 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets *
size_t newSize = file->getSize();
float factor = ((float)newSize)/oldSize;
int percent = (int)(factor*100);
- printf(" (processed image %s: %d%% size of source)\n", printableName.string(), percent);
+ printf(" (processed image %s: %d%% size of source)\n", printableName.c_str(), percent);
}
bail:
@@ -1450,7 +1450,7 @@ bail:
if (error != NO_ERROR) {
fprintf(stderr, "ERROR: Failure processing PNG image %s\n",
- file->getPrintableSource().string());
+ file->getPrintableSource().c_str());
}
return error;
}
@@ -1470,13 +1470,13 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
status_t error = UNKNOWN_ERROR;
if (bundle->getVerbose()) {
- printf("Processing image to cache: %s => %s\n", source.string(), dest.string());
+ printf("Processing image to cache: %s => %s\n", source.c_str(), dest.c_str());
}
// Get a file handler to read from
- fp = fopen(source.string(),"rb");
+ fp = fopen(source.c_str(),"rb");
if (fp == NULL) {
- fprintf(stderr, "%s ERROR: Unable to open PNG file\n", source.string());
+ fprintf(stderr, "%s ERROR: Unable to open PNG file\n", source.c_str());
return error;
}
@@ -1507,7 +1507,7 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
png_init_io(read_ptr,fp);
// Actually read data from the file
- read_png(source.string(), read_ptr, read_info, &imageInfo);
+ read_png(source.c_str(), read_ptr, read_info, &imageInfo);
// We're done reading so we can clean up
// Find old file size before releasing handle
@@ -1519,7 +1519,7 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
// Check to see if we're dealing with a 9-patch
// If we are, process appropriately
if (source.getBasePath().getPathExtension() == ".9") {
- if (do_9patch(source.string(), &imageInfo) != NO_ERROR) {
+ if (do_9patch(source.c_str(), &imageInfo) != NO_ERROR) {
return error;
}
}
@@ -1541,9 +1541,9 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
}
// Open up our destination file for writing
- fp = fopen(dest.string(), "wb");
+ fp = fopen(dest.c_str(), "wb");
if (!fp) {
- fprintf(stderr, "%s ERROR: Unable to open PNG file\n", dest.string());
+ fprintf(stderr, "%s ERROR: Unable to open PNG file\n", dest.c_str());
png_destroy_write_struct(&write_ptr, &write_info);
return error;
}
@@ -1559,11 +1559,11 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
}
// Actually write out to the new png
- write_png(dest.string(), write_ptr, write_info, imageInfo, bundle);
+ write_png(dest.c_str(), write_ptr, write_info, imageInfo, bundle);
if (bundle->getVerbose()) {
// Find the size of our new file
- FILE* reader = fopen(dest.string(), "rb");
+ FILE* reader = fopen(dest.c_str(), "rb");
fseek(reader, 0, SEEK_END);
size_t newSize = (size_t)ftell(reader);
fclose(reader);
@@ -1571,7 +1571,7 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
float factor = ((float)newSize)/oldSize;
int percent = (int)(factor*100);
printf(" (processed image to cache entry %s: %d%% size of source)\n",
- dest.string(), percent);
+ dest.c_str(), percent);
}
//Clean up
@@ -1588,7 +1588,7 @@ status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
// At this point, now that we have all the resource data, all we need to
// do is compile XML files.
- if (strcmp(ext.string(), ".xml") == 0) {
+ if (strcmp(ext.c_str(), ".xml") == 0) {
String16 resourceName(parseResourceName(file->getSourceFile().getPathLeaf()));
return compileXmlFile(bundle, assets, resourceName, file, table);
}
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index f06643dcf784..965655b59a94 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -69,39 +69,39 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
* If "update" is set, update the contents of the existing archive.
* Else, if "force" is set, remove the existing archive.
*/
- FileType fileType = getFileType(outputFile.string());
+ FileType fileType = getFileType(outputFile.c_str());
if (fileType == kFileTypeNonexistent) {
// okay, create it below
} else if (fileType == kFileTypeRegular) {
if (bundle->getUpdate()) {
// okay, open it below
} else if (bundle->getForce()) {
- if (unlink(outputFile.string()) != 0) {
- fprintf(stderr, "ERROR: unable to remove '%s': %s\n", outputFile.string(),
+ if (unlink(outputFile.c_str()) != 0) {
+ fprintf(stderr, "ERROR: unable to remove '%s': %s\n", outputFile.c_str(),
strerror(errno));
goto bail;
}
} else {
fprintf(stderr, "ERROR: '%s' exists (use '-f' to force overwrite)\n",
- outputFile.string());
+ outputFile.c_str());
goto bail;
}
} else {
- fprintf(stderr, "ERROR: '%s' exists and is not a regular file\n", outputFile.string());
+ fprintf(stderr, "ERROR: '%s' exists and is not a regular file\n", outputFile.c_str());
goto bail;
}
if (bundle->getVerbose()) {
printf("%s '%s'\n", (fileType == kFileTypeNonexistent) ? "Creating" : "Opening",
- outputFile.string());
+ outputFile.c_str());
}
status_t status;
zip = new ZipFile;
- status = zip->open(outputFile.string(), ZipFile::kOpenReadWrite | ZipFile::kOpenCreate);
+ status = zip->open(outputFile.c_str(), ZipFile::kOpenReadWrite | ZipFile::kOpenCreate);
if (status != NO_ERROR) {
fprintf(stderr, "ERROR: unable to open '%s' as Zip file for writing\n",
- outputFile.string());
+ outputFile.c_str());
goto bail;
}
@@ -112,7 +112,7 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
count = processAssets(bundle, zip, outputSet);
if (count < 0) {
fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
- outputFile.string());
+ outputFile.c_str());
result = count;
goto bail;
}
@@ -124,7 +124,7 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
count = processJarFiles(bundle, zip);
if (count < 0) {
fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n",
- outputFile.string());
+ outputFile.c_str());
result = count;
goto bail;
}
@@ -169,12 +169,12 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
/* anything here? */
if (zip->getNumEntries() == 0) {
if (bundle->getVerbose()) {
- printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().string());
+ printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().c_str());
}
delete zip; // close the file so we can remove it in Win32
zip = NULL;
- if (unlink(outputFile.string()) != 0) {
- fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
+ if (unlink(outputFile.c_str()) != 0) {
+ fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.c_str());
}
}
@@ -187,9 +187,9 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
String8 dependencyFile = outputFile;
dependencyFile.append(".d");
- FILE* fp = fopen(dependencyFile.string(), "a");
+ FILE* fp = fopen(dependencyFile.c_str(), "a");
// Add this file to the dependency file
- fprintf(fp, "%s \\\n", outputFile.string());
+ fprintf(fp, "%s \\\n", outputFile.c_str());
fclose(fp);
}
@@ -199,10 +199,10 @@ bail:
delete zip; // must close before remove in Win32
if (result != NO_ERROR) {
if (bundle->getVerbose()) {
- printf("Removing %s due to earlier failures\n", outputFile.string());
+ printf("Removing %s due to earlier failures\n", outputFile.c_str());
}
- if (unlink(outputFile.string()) != 0) {
- fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
+ if (unlink(outputFile.c_str()) != 0) {
+ fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.c_str());
}
}
@@ -267,31 +267,31 @@ bool processFile(Bundle* bundle, ZipFile* zip,
int fileNameLen = storageName.length();
int excludeExtensionLen = strlen(kExcludeExtension);
if (fileNameLen > excludeExtensionLen
- && (0 == strcmp(storageName.string() + (fileNameLen - excludeExtensionLen),
+ && (0 == strcmp(storageName.c_str() + (fileNameLen - excludeExtensionLen),
kExcludeExtension))) {
- fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.string());
+ fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.c_str());
return true;
}
- if (strcasecmp(storageName.getPathExtension().string(), ".gz") == 0) {
+ if (strcasecmp(storageName.getPathExtension().c_str(), ".gz") == 0) {
fromGzip = true;
storageName = storageName.getBasePath();
}
if (bundle->getUpdate()) {
- entry = zip->getEntryByName(storageName.string());
+ entry = zip->getEntryByName(storageName.c_str());
if (entry != NULL) {
/* file already exists in archive; there can be only one */
if (entry->getMarked()) {
fprintf(stderr,
"ERROR: '%s' exists twice (check for with & w/o '.gz'?)\n",
- file->getPrintableSource().string());
+ file->getPrintableSource().c_str());
return false;
}
if (!hasData) {
const String8& srcName = file->getSourceFile();
time_t fileModWhen;
- fileModWhen = getFileModDate(srcName.string());
+ fileModWhen = getFileModDate(srcName.c_str());
if (fileModWhen == (time_t) -1) { // file existence tested earlier,
return false; // not expecting an error here
}
@@ -299,14 +299,14 @@ bool processFile(Bundle* bundle, ZipFile* zip,
if (fileModWhen > entry->getModWhen()) {
// mark as deleted so add() will succeed
if (bundle->getVerbose()) {
- printf(" (removing old '%s')\n", storageName.string());
+ printf(" (removing old '%s')\n", storageName.c_str());
}
zip->remove(entry);
} else {
// version in archive is newer
if (bundle->getVerbose()) {
- printf(" (not updating '%s')\n", storageName.string());
+ printf(" (not updating '%s')\n", storageName.c_str());
}
entry->setMarked(true);
return true;
@@ -321,22 +321,22 @@ bool processFile(Bundle* bundle, ZipFile* zip,
//android_setMinPriority(NULL, ANDROID_LOG_VERBOSE);
if (fromGzip) {
- result = zip->addGzip(file->getSourceFile().string(), storageName.string(), &entry);
+ result = zip->addGzip(file->getSourceFile().c_str(), storageName.c_str(), &entry);
} else if (!hasData) {
/* don't compress certain files, e.g. PNGs */
int compressionMethod = bundle->getCompressionMethod();
if (!okayToCompress(bundle, storageName)) {
compressionMethod = ZipEntry::kCompressStored;
}
- result = zip->add(file->getSourceFile().string(), storageName.string(), compressionMethod,
+ result = zip->add(file->getSourceFile().c_str(), storageName.c_str(), compressionMethod,
&entry);
} else {
- result = zip->add(file->getData(), file->getSize(), storageName.string(),
+ result = zip->add(file->getData(), file->getSize(), storageName.c_str(),
file->getCompressionMethod(), &entry);
}
if (result == NO_ERROR) {
if (bundle->getVerbose()) {
- printf(" '%s'%s", storageName.string(), fromGzip ? " (from .gz)" : "");
+ printf(" '%s'%s", storageName.c_str(), fromGzip ? " (from .gz)" : "");
if (entry->getCompressionMethod() == ZipEntry::kCompressStored) {
printf(" (not compressed)\n");
} else {
@@ -348,10 +348,10 @@ bool processFile(Bundle* bundle, ZipFile* zip,
} else {
if (result == ALREADY_EXISTS) {
fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n",
- file->getPrintableSource().string());
+ file->getPrintableSource().c_str());
} else {
fprintf(stderr, " Unable to add '%s': Zip add failed (%d)\n",
- file->getPrintableSource().string(), result);
+ file->getPrintableSource().c_str(), result);
}
return false;
}
@@ -372,7 +372,7 @@ bool okayToCompress(Bundle* bundle, const String8& pathName)
return true;
for (i = 0; i < NELEM(kNoCompressExt); i++) {
- if (strcasecmp(ext.string(), kNoCompressExt[i]) == 0)
+ if (strcasecmp(ext.c_str(), kNoCompressExt[i]) == 0)
return false;
}
@@ -383,7 +383,7 @@ bool okayToCompress(Bundle* bundle, const String8& pathName)
if (pos < 0) {
continue;
}
- const char* path = pathName.string();
+ const char* path = pathName.c_str();
if (strcasecmp(path + pos, str) == 0) {
return false;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index dd3ebdbdea09..4ca3a68d02a6 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -57,8 +57,8 @@ public:
String8 parseResourceName(const String8& leaf)
{
- const char* firstDot = strchr(leaf.string(), '.');
- const char* str = leaf.string();
+ const char* firstDot = strchr(leaf.c_str(), '.');
+ const char* str = leaf.c_str();
if (firstDot) {
return String8(str, firstDot-str);
@@ -132,7 +132,7 @@ public:
mParams = file->getGroupEntry().toParams();
if (kIsDebug) {
printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n",
- group->getPath().string(), mParams.mcc, mParams.mnc,
+ group->getPath().c_str(), mParams.mcc, mParams.mnc,
mParams.language[0] ? mParams.language[0] : '-',
mParams.language[1] ? mParams.language[1] : '-',
mParams.country[0] ? mParams.country[0] : '-',
@@ -147,12 +147,12 @@ public:
mBaseName = parseResourceName(leaf);
if (mBaseName == "") {
fprintf(stderr, "Error: malformed resource filename %s\n",
- file->getPrintableSource().string());
+ file->getPrintableSource().c_str());
return UNKNOWN_ERROR;
}
if (kIsDebug) {
- printf("file name=%s\n", mBaseName.string());
+ printf("file name=%s\n", mBaseName.c_str());
}
return NO_ERROR;
@@ -222,7 +222,7 @@ static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
{
if (grp->getFiles().size() != 1) {
fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
- grp->getFiles().valueAt(0)->getPrintableSource().string());
+ grp->getFiles().valueAt(0)->getPrintableSource().c_str());
}
sp<AaptFile> file = grp->getFiles().valueAt(0);
@@ -243,20 +243,20 @@ static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
size_t len;
if (code != ResXMLTree::START_TAG) {
fprintf(stderr, "%s:%d: No start tag found\n",
- file->getPrintableSource().string(), block.getLineNumber());
+ file->getPrintableSource().c_str(), block.getLineNumber());
return UNKNOWN_ERROR;
}
- if (strcmp16(block.getElementName(&len), String16("manifest").string()) != 0) {
+ if (strcmp16(block.getElementName(&len), String16("manifest").c_str()) != 0) {
fprintf(stderr, "%s:%d: Invalid start tag %s, expected <manifest>\n",
- file->getPrintableSource().string(), block.getLineNumber(),
- String8(block.getElementName(&len)).string());
+ file->getPrintableSource().c_str(), block.getLineNumber(),
+ String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
ssize_t nameIndex = block.indexOfAttribute(NULL, "package");
if (nameIndex < 0) {
fprintf(stderr, "%s:%d: <manifest> does not have package attribute.\n",
- file->getPrintableSource().string(), block.getLineNumber());
+ file->getPrintableSource().c_str(), block.getLineNumber());
return UNKNOWN_ERROR;
}
@@ -264,19 +264,19 @@ static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
ssize_t revisionCodeIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "revisionCode");
if (revisionCodeIndex >= 0) {
- bundle->setRevisionCode(String8(block.getAttributeStringValue(revisionCodeIndex, &len)).string());
+ bundle->setRevisionCode(String8(block.getAttributeStringValue(revisionCodeIndex, &len)).c_str());
}
String16 uses_sdk16("uses-sdk");
while ((code=block.next()) != ResXMLTree::END_DOCUMENT
&& code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
- if (strcmp16(block.getElementName(&len), uses_sdk16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), uses_sdk16.c_str()) == 0) {
ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
"minSdkVersion");
if (minSdkIndex >= 0) {
const char16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len);
- const char* minSdk8 = strdup(String8(minSdk16).string());
+ const char* minSdk8 = strdup(String8(minSdk16).c_str());
bundle->setManifestMinSdkVersion(minSdk8);
}
}
@@ -305,17 +305,17 @@ static status_t makeFileResources(Bundle* bundle, const sp<AaptAssets>& assets,
while ((res=it.next()) == NO_ERROR) {
if (bundle->getVerbose()) {
printf(" (new resource id %s from %s)\n",
- it.getBaseName().string(), it.getFile()->getPrintableSource().string());
+ it.getBaseName().c_str(), it.getFile()->getPrintableSource().c_str());
}
String16 baseName(it.getBaseName());
- const char16_t* str = baseName.string();
+ const char16_t* str = baseName.c_str();
const char16_t* const end = str + baseName.size();
while (str < end) {
if (!((*str >= 'a' && *str <= 'z')
|| (*str >= '0' && *str <= '9')
|| *str == '_' || *str == '.')) {
fprintf(stderr, "%s: Invalid file name: must contain only [a-z0-9_.]\n",
- it.getPath().string());
+ it.getPath().c_str());
hasErrors = true;
}
str++;
@@ -413,7 +413,7 @@ static void collect_files(const sp<AaptDir>& dir,
sp<ResourceTypeSet> set = new ResourceTypeSet();
if (kIsDebug) {
printf("Creating new resource type set for leaf %s with group %s (%p)\n",
- leafName.string(), group->getPath().string(), group.get());
+ leafName.c_str(), group->getPath().c_str(), group.get());
}
set->add(leafName, group);
resources->add(resType, set);
@@ -423,21 +423,21 @@ static void collect_files(const sp<AaptDir>& dir,
if (index < 0) {
if (kIsDebug) {
printf("Adding to resource type set for leaf %s group %s (%p)\n",
- leafName.string(), group->getPath().string(), group.get());
+ leafName.c_str(), group->getPath().c_str(), group.get());
}
set->add(leafName, group);
} else {
sp<AaptGroup> existingGroup = set->valueAt(index);
if (kIsDebug) {
printf("Extending to resource type set for leaf %s group %s (%p)\n",
- leafName.string(), group->getPath().string(), group.get());
+ leafName.c_str(), group->getPath().c_str(), group.get());
}
for (size_t j=0; j<files.size(); j++) {
if (kIsDebug) {
printf("Adding file %s in group %s resType %s\n",
- files.valueAt(j)->getSourceFile().string(),
- files.keyAt(j).toDirName(String8()).string(),
- resType.string());
+ files.valueAt(j)->getSourceFile().c_str(),
+ files.keyAt(j).toDirName(String8()).c_str(),
+ resType.c_str());
}
existingGroup->addFile(files.valueAt(j));
}
@@ -455,14 +455,14 @@ static void collect_files(const sp<AaptAssets>& ass,
for (int i=0; i<N; i++) {
const sp<AaptDir>& d = dirs.itemAt(i);
if (kIsDebug) {
- printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(),
- d->getLeaf().string());
+ printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().c_str(),
+ d->getLeaf().c_str());
}
collect_files(d, resources);
// don't try to include the res dir
if (kIsDebug) {
- printf("Removing dir leaf %s\n", d->getLeaf().string());
+ printf("Removing dir leaf %s\n", d->getLeaf().c_str());
}
ass->removeDir(d->getLeaf());
}
@@ -490,8 +490,8 @@ static int validateAttr(const String8& path, const ResTable& table,
int strIdx;
if ((strIdx=table.resolveReference(&value, 0x10000000, NULL, &specFlags)) < 0) {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s references unknown resid 0x%08x.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr,
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr,
value.data);
return ATTR_NOT_FOUND;
}
@@ -502,12 +502,12 @@ static int validateAttr(const String8& path, const ResTable& table,
str = pool->stringAt(value.data, &len);
}
printf("***** RES ATTR: %s specFlags=0x%x strIdx=%d: %s\n", attr,
- specFlags, strIdx, str != NULL ? String8(str).string() : "???");
+ specFlags, strIdx, str != NULL ? String8(str).c_str() : "???");
#endif
if ((specFlags&~ResTable_typeSpec::SPEC_PUBLIC) != 0 && false) {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s varies by configurations 0x%x.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr,
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr,
specFlags);
return ATTR_NOT_FOUND;
}
@@ -515,20 +515,20 @@ static int validateAttr(const String8& path, const ResTable& table,
if (value.dataType == Res_value::TYPE_STRING) {
if (pool == NULL) {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s has no string block.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr);
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr);
return ATTR_NOT_FOUND;
}
if ((str = UnpackOptionalString(pool->stringAt(value.data), &len)) == NULL) {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr);
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr);
return ATTR_NOT_FOUND;
}
} else {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s has invalid type %d.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr,
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr,
value.dataType);
return ATTR_NOT_FOUND;
}
@@ -546,30 +546,30 @@ static int validateAttr(const String8& path, const ResTable& table,
}
if (!okay) {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s has invalid character '%c'.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr, (char)str[i]);
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr, (char)str[i]);
return (int)i;
}
}
}
if (*str == ' ') {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not start with a space.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr);
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr);
return ATTR_LEADING_SPACES;
}
if (len != 0 && str[len-1] == ' ') {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not end with a space.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr);
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr);
return ATTR_TRAILING_SPACES;
}
return ATTR_OKAY;
}
if (required) {
fprintf(stderr, "%s:%d: Tag <%s> missing required attribute %s.\n",
- path.string(), parser.getLineNumber(),
- String8(parser.getElementName(&len)).string(), attr);
+ path.c_str(), parser.getLineNumber(),
+ String8(parser.getElementName(&len)).c_str(), attr);
return ATTR_NOT_FOUND;
}
return ATTR_OKAY;
@@ -584,7 +584,7 @@ static void checkForIds(const String8& path, ResXMLParser& parser)
ssize_t index = parser.indexOfAttribute(NULL, "id");
if (index >= 0) {
fprintf(stderr, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
- path.string(), parser.getLineNumber());
+ path.c_str(), parser.getLineNumber());
}
}
}
@@ -618,7 +618,7 @@ static bool applyFileOverlay(Bundle *bundle,
size_t overlayCount = overlaySet->size();
for (size_t overlayIndex=0; overlayIndex<overlayCount; overlayIndex++) {
if (bundle->getVerbose()) {
- printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string());
+ printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).c_str());
}
ssize_t baseIndex = -1;
if (baseSet->get() != NULL) {
@@ -638,11 +638,11 @@ static bool applyFileOverlay(Bundle *bundle,
baseGroup->getFiles();
for (size_t i=0; i < baseFiles.size(); i++) {
printf("baseFile " ZD " has flavor %s\n", (ZD_TYPE) i,
- baseFiles.keyAt(i).toString().string());
+ baseFiles.keyAt(i).toString().c_str());
}
for (size_t i=0; i < overlayFiles.size(); i++) {
printf("overlayFile " ZD " has flavor %s\n", (ZD_TYPE) i,
- overlayFiles.keyAt(i).toString().string());
+ overlayFiles.keyAt(i).toString().c_str());
}
}
@@ -657,16 +657,16 @@ static bool applyFileOverlay(Bundle *bundle,
if (bundle->getVerbose()) {
printf("found a match (" ZD ") for overlay file %s, for flavor %s\n",
(ZD_TYPE) baseFileIndex,
- overlayGroup->getLeaf().string(),
- overlayFiles.keyAt(overlayGroupIndex).toString().string());
+ overlayGroup->getLeaf().c_str(),
+ overlayFiles.keyAt(overlayGroupIndex).toString().c_str());
}
baseGroup->removeFile(baseFileIndex);
} else {
// didn't find a match fall through and add it..
if (true || bundle->getVerbose()) {
printf("nothing matches overlay file %s, for flavor %s\n",
- overlayGroup->getLeaf().string(),
- overlayFiles.keyAt(overlayGroupIndex).toString().string());
+ overlayGroup->getLeaf().c_str(),
+ overlayFiles.keyAt(overlayGroupIndex).toString().c_str());
}
}
baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex));
@@ -728,7 +728,7 @@ bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
if (errorOnFailedInsert) {
fprintf(stderr, "Error: AndroidManifest.xml already defines %s (in %s);"
" cannot insert new value %s.\n",
- String8(attr).string(), String8(ns).string(), value);
+ String8(attr).c_str(), String8(ns).c_str(), value);
return false;
}
@@ -763,7 +763,7 @@ static void fullyQualifyClassName(const String8& package, const sp<XMLNode>& nod
// .asdf .a.b --> package.asdf package.a.b
// asdf.adsf --> asdf.asdf
String8 className;
- const char* p = name.string();
+ const char* p = name.c_str();
const char* q = strchr(p, '.');
if (p == q) {
className += package;
@@ -776,7 +776,7 @@ static void fullyQualifyClassName(const String8& package, const sp<XMLNode>& nod
className += name;
}
if (kIsDebug) {
- printf("Qualifying class '%s' to '%s'", name.string(), className.string());
+ printf("Qualifying class '%s' to '%s'", name.c_str(), className.c_str());
}
attr->string.setTo(String16(className));
}
@@ -810,7 +810,7 @@ static void massageRoundIconSupport(const String16& iconRef, const String16& rou
const char* err;
String16 iconPackage, iconType, iconName;
- if (!ResTable::expandResourceRef(iconRef.string(), iconRef.size(), &iconPackage, &iconType,
+ if (!ResTable::expandResourceRef(iconRef.c_str(), iconRef.size(), &iconPackage, &iconType,
&iconName, NULL, &table->getAssetsPackage(), &err,
&publicOnly)) {
// Errors will be raised in later XML compilation.
@@ -824,7 +824,7 @@ static void massageRoundIconSupport(const String16& iconRef, const String16& rou
}
String16 roundIconPackage, roundIconType, roundIconName;
- if (!ResTable::expandResourceRef(roundIconRef.string(), roundIconRef.size(), &roundIconPackage,
+ if (!ResTable::expandResourceRef(roundIconRef.c_str(), roundIconRef.size(), &roundIconPackage,
&roundIconType, &roundIconName, NULL, &table->getAssetsPackage(),
&err, &publicOnly)) {
// Errors will be raised in later XML compilation.
@@ -839,9 +839,9 @@ static void massageRoundIconSupport(const String16& iconRef, const String16& rou
return;
}
- String16 aliasValue = String16(String8::format("@%s:%s/%s", String8(iconPackage).string(),
- String8(iconType).string(),
- String8(iconName).string()));
+ String16 aliasValue = String16(String8::format("@%s:%s/%s", String8(iconPackage).c_str(),
+ String8(iconType).c_str(),
+ String8(iconName).c_str()));
// Add an equivalent v26 entry to the roundIcon for each v26 variant of the regular icon.
const DefaultKeyedVector<ConfigDescription, sp<ResourceTable::Entry>>& configList =
@@ -872,7 +872,7 @@ status_t massageManifest(Bundle* bundle, ResourceTable* table, sp<XMLNode> root)
const XMLNode::attribute_entry* attr = root->getAttribute(
String16(RESOURCES_ANDROID_NAMESPACE), String16("versionCode"));
if (attr != NULL) {
- bundle->setVersionCode(strdup(String8(attr->string).string()));
+ bundle->setVersionCode(strdup(String8(attr->string).c_str()));
}
}
@@ -883,7 +883,7 @@ status_t massageManifest(Bundle* bundle, ResourceTable* table, sp<XMLNode> root)
const XMLNode::attribute_entry* attr = root->getAttribute(
String16(RESOURCES_ANDROID_NAMESPACE), String16("versionName"));
if (attr != NULL) {
- bundle->setVersionName(strdup(String8(attr->string).string()));
+ bundle->setVersionName(strdup(String8(attr->string).c_str()));
}
}
@@ -914,7 +914,7 @@ status_t massageManifest(Bundle* bundle, ResourceTable* table, sp<XMLNode> root)
const XMLNode::attribute_entry* attr = vers->getAttribute(
String16(RESOURCES_ANDROID_NAMESPACE), String16("minSdkVersion"));
if (attr != NULL) {
- bundle->setMinSdkVersion(strdup(String8(attr->string).string()));
+ bundle->setMinSdkVersion(strdup(String8(attr->string).c_str()));
}
}
@@ -970,7 +970,7 @@ status_t massageManifest(Bundle* bundle, ResourceTable* table, sp<XMLNode> root)
String8 origPackage(attr->string);
attr->string.setTo(String16(manifestPackageNameOverride));
if (kIsDebug) {
- printf("Overriding package '%s' to be '%s'\n", origPackage.string(),
+ printf("Overriding package '%s' to be '%s'\n", origPackage.c_str(),
manifestPackageNameOverride);
}
@@ -1071,7 +1071,7 @@ enum {
static ssize_t extractPlatformBuildVersion(const ResTable& table, ResXMLTree& tree, Bundle* bundle) {
// First check if we should be recording the compileSdkVersion* attributes.
static const String16 compileSdkVersionName("android:attr/compileSdkVersion");
- const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.string(),
+ const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.c_str(),
compileSdkVersionName.size()) != 0u;
size_t len;
@@ -1223,7 +1223,7 @@ status_t generateAndroidManifestForSplit(Bundle* bundle, const sp<AaptAssets>& a
// Add the 'revisionCode' attribute, which is set to the original revisionCode.
if (bundle->getRevisionCode().size() > 0) {
if (!addTagAttribute(manifest, RESOURCES_ANDROID_NAMESPACE, "revisionCode",
- bundle->getRevisionCode().string(), true, true)) {
+ bundle->getRevisionCode().c_str(), true, true)) {
return UNKNOWN_ERROR;
}
}
@@ -1270,7 +1270,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
}
if (kIsDebug) {
- printf("Creating resources for package %s\n", assets->getPackage().string());
+ printf("Creating resources for package %s\n", assets->getPackage().c_str());
}
// Set the private symbols package if it was declared.
@@ -1804,7 +1804,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
flattenedTable, split->isBase());
if (err != NO_ERROR) {
fprintf(stderr, "Failed to generate resource table for split '%s'\n",
- split->getPrintableName().string());
+ split->getPrintableName().c_str());
return err;
}
split->addEntry(String8("resources.arsc"), flattenedTable);
@@ -1821,7 +1821,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
err = resTable.add(flattenedTable->getData(), flattenedTable->getSize());
if (err != NO_ERROR) {
fprintf(stderr, "Generated resource table for split '%s' is corrupt.\n",
- split->getPrintableName().string());
+ split->getPrintableName().c_str());
return err;
}
@@ -1849,7 +1849,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
if (block < 0) {
hasError = true;
SourcePos().error("%s has no definition for density split '%s'",
- symbol.toString().string(), config.toString().string());
+ symbol.toString().c_str(), config.toString().c_str());
if (bundle->getVerbose()) {
const Vector<SymbolDefinition>& defs = densityVaryingResources[k];
@@ -1857,7 +1857,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
for (size_t d = 0; d < defCount; d++) {
const SymbolDefinition& def = defs[d];
def.source.error("%s has definition for %s",
- symbol.toString().string(), def.config.toString().string());
+ symbol.toString().c_str(), def.config.toString().c_str());
}
if (defCount < defs.size()) {
@@ -1880,7 +1880,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
generatedManifest, &table);
if (err != NO_ERROR) {
fprintf(stderr, "Failed to generate AndroidManifest.xml for split '%s'\n",
- split->getPrintableName().string());
+ split->getPrintableName().c_str());
return err;
}
split->addEntry(String8("AndroidManifest.xml"), generatedManifest);
@@ -1960,7 +1960,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
if (block.getElementNamespace(&len) != NULL) {
continue;
}
- if (strcmp16(block.getElementName(&len), manifest16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), manifest16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block, NULL, "package",
packageIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
@@ -1969,10 +1969,10 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
"sharedUserId", packageIdentChars, false) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), permission16.string()) == 0
- || strcmp16(block.getElementName(&len), permission_group16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), permission16.c_str()) == 0
+ || strcmp16(block.getElementName(&len), permission_group16.c_str()) == 0) {
const bool isGroup = strcmp16(block.getElementName(&len),
- permission_group16.string()) == 0;
+ permission_group16.c_str()) == 0;
if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
"name", isGroup ? packageIdentCharsWithTheStupid
: packageIdentChars, true) != ATTR_OKAY) {
@@ -2002,8 +2002,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
const char16_t* id = block.getAttributeStringValue(index, &len);
if (id == NULL) {
fprintf(stderr, "%s:%d: missing name attribute in element <%s>.\n",
- manifestPath.string(), block.getLineNumber(),
- String8(block.getElementName(&len)).string());
+ manifestPath.c_str(), block.getLineNumber(),
+ String8(block.getElementName(&len)).c_str());
hasErrors = true;
break;
}
@@ -2038,23 +2038,23 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
if (begins_with_digit || (e != p && *(e-1) != '.')) {
fprintf(stderr,
"%s:%d: Permission name <%s> is not a valid Java symbol\n",
- manifestPath.string(), block.getLineNumber(), idStr.string());
+ manifestPath.c_str(), block.getLineNumber(), idStr.c_str());
hasErrors = true;
}
syms->addStringSymbol(String8(e), idStr, srcPos);
const char16_t* cmt = block.getComment(&len);
if (cmt != NULL && *cmt != 0) {
- //printf("Comment of %s: %s\n", String8(e).string(),
- // String8(cmt).string());
+ //printf("Comment of %s: %s\n", String8(e).c_str(),
+ // String8(cmt).c_str());
syms->appendComment(String8(e), String16(cmt), srcPos);
}
syms->makeSymbolPublic(String8(e), srcPos);
- } else if (strcmp16(block.getElementName(&len), uses_permission16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), uses_permission16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
"name", packageIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), instrumentation16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), instrumentation16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
"name", classIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
@@ -2064,7 +2064,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
packageIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), application16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), application16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
"name", classIdentChars, false) != ATTR_OKAY) {
hasErrors = true;
@@ -2084,7 +2084,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
processIdentChars, false) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), provider16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), provider16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
"name", classIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
@@ -2104,9 +2104,9 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
processIdentChars, false) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), service16.string()) == 0
- || strcmp16(block.getElementName(&len), receiver16.string()) == 0
- || strcmp16(block.getElementName(&len), activity16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), service16.c_str()) == 0
+ || strcmp16(block.getElementName(&len), receiver16.c_str()) == 0
+ || strcmp16(block.getElementName(&len), activity16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
"name", classIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
@@ -2126,14 +2126,14 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
processIdentChars, false) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), action16.string()) == 0
- || strcmp16(block.getElementName(&len), category16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), action16.c_str()) == 0
+ || strcmp16(block.getElementName(&len), category16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block,
RESOURCES_ANDROID_NAMESPACE, "name",
packageIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), data16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), data16.c_str()) == 0) {
if (validateAttr(manifestPath, finalResTable, block,
RESOURCES_ANDROID_NAMESPACE, "mimeType",
typeIdentChars, true) != ATTR_OKAY) {
@@ -2144,13 +2144,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
schemeIdentChars, true) != ATTR_OKAY) {
hasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), feature_group16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), feature_group16.c_str()) == 0) {
int depth = 1;
while ((code=block.next()) != ResXMLTree::END_DOCUMENT
&& code > ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
depth++;
- if (strcmp16(block.getElementName(&len), uses_feature16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), uses_feature16.c_str()) == 0) {
ssize_t idx = block.indexOfAttribute(
RESOURCES_ANDROID_NAMESPACE, "required");
if (idx < 0) {
@@ -2162,7 +2162,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
fprintf(stderr, "%s:%d: Tag <uses-feature> can not have "
"android:required=\"false\" when inside a "
"<feature-group> tag.\n",
- manifestPath.string(), block.getLineNumber());
+ manifestPath.c_str(), block.getLineNumber());
hasErrors = true;
}
}
@@ -2222,7 +2222,7 @@ static String8 flattenSymbol(const String8& symbol) {
static String8 getSymbolPackage(const String8& symbol, const sp<AaptAssets>& assets, bool pub) {
ssize_t colon = symbol.find(":", 0);
if (colon >= 0) {
- return String8(symbol.string(), colon);
+ return String8(symbol.c_str(), colon);
}
return pub ? assets->getPackage() : assets->getSymbolsPrivatePackage();
}
@@ -2230,7 +2230,7 @@ static String8 getSymbolPackage(const String8& symbol, const sp<AaptAssets>& ass
static String8 getSymbolName(const String8& symbol) {
ssize_t colon = symbol.find(":", 0);
if (colon >= 0) {
- return String8(symbol.string() + colon + 1);
+ return String8(symbol.c_str() + colon + 1);
}
return symbol;
}
@@ -2245,7 +2245,7 @@ static String16 getAttributeComment(const sp<AaptAssets>& assets,
asym = asym->getNestedSymbols().valueFor(String8("attr"));
if (asym != NULL) {
//printf("Got attrs symbols! comment %s=%s\n",
- // name.string(), String8(asym->getComment(name)).string());
+ // name.c_str(), String8(asym->getComment(name)).c_str());
if (outTypeComment != NULL) {
*outTypeComment = asym->getTypeComment(name);
}
@@ -2276,8 +2276,8 @@ static status_t writeResourceLoadedCallbackForLayoutClasses(
"%sfor(int i = 0; i < styleable.%s.length; ++i) {\n"
"%sstyleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | (packageId << 24);\n"
"%s}\n",
- indentStr, nclassName.string(),
- getIndentSpace(indent+1), nclassName.string(), nclassName.string(),
+ indentStr, nclassName.c_str(),
+ getIndentSpace(indent+1), nclassName.c_str(), nclassName.c_str(),
indentStr);
}
@@ -2303,8 +2303,8 @@ static status_t writeResourceLoadedCallback(
String8 flat_name(flattenSymbol(sym.name));
fprintf(fp,
"%s%s.%s = (%s.%s & 0x00ffffff) | (packageId << 24);\n",
- getIndentSpace(indent), className.string(), flat_name.string(),
- className.string(), flat_name.string());
+ getIndentSpace(indent), className.c_str(), flat_name.c_str(),
+ className.c_str(), flat_name.c_str());
}
N = symbols->getNestedSymbols().size();
@@ -2365,12 +2365,12 @@ static status_t writeLayoutClasses(
String16 name16(sym.name);
uint32_t typeSpecFlags;
code = assets->getIncludedResources().identifierForName(
- name16.string(), name16.size(),
- attr16.string(), attr16.size(),
- package16.string(), package16.size(), &typeSpecFlags);
+ name16.c_str(), name16.size(),
+ attr16.c_str(), attr16.size(),
+ package16.c_str(), package16.size(), &typeSpecFlags);
if (code == 0) {
fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n",
- nclassName.string(), sym.name.string());
+ nclassName.c_str(), sym.name.c_str());
hasErrors = true;
}
isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
@@ -2388,9 +2388,9 @@ static status_t writeLayoutClasses(
if (comment.size() > 0) {
String8 cmt(comment);
ann.preprocessComment(cmt);
- fprintf(fp, "%s\n", cmt.string());
+ fprintf(fp, "%s\n", cmt.c_str());
} else {
- fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string());
+ fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.c_str());
}
bool hasTable = false;
for (a=0; a<NA; a++) {
@@ -2423,7 +2423,7 @@ static status_t writeLayoutClasses(
continue;
}
if (comment.size() > 0) {
- const char16_t* p = comment.string();
+ const char16_t* p = comment.c_str();
while (*p != 0 && *p != '.') {
if (*p == '{') {
while (*p != 0 && *p != '}') {
@@ -2436,14 +2436,14 @@ static status_t writeLayoutClasses(
if (*p == '.') {
p++;
}
- comment = String16(comment.string(), p-comment.string());
+ comment = String16(comment.c_str(), p-comment.c_str());
}
fprintf(fp, "%s <tr><td><code>{@link #%s_%s %s:%s}</code></td><td>%s</td></tr>\n",
- indentStr, nclassName.string(),
- flattenSymbol(name8).string(),
- getSymbolPackage(name8, assets, true).string(),
- getSymbolName(name8).string(),
- String8(comment).string());
+ indentStr, nclassName.c_str(),
+ flattenSymbol(name8).c_str(),
+ getSymbolPackage(name8, assets, true).c_str(),
+ getSymbolName(name8).c_str(),
+ String8(comment).c_str());
}
}
if (hasTable) {
@@ -2457,8 +2457,8 @@ static status_t writeLayoutClasses(
continue;
}
fprintf(fp, "%s @see #%s_%s\n",
- indentStr, nclassName.string(),
- flattenSymbol(sym.name).string());
+ indentStr, nclassName.c_str(),
+ flattenSymbol(sym.name).c_str());
}
}
fprintf(fp, "%s */\n", getIndentSpace(indent));
@@ -2468,7 +2468,7 @@ static status_t writeLayoutClasses(
fprintf(fp,
"%spublic static final int[] %s = {\n"
"%s",
- indentStr, nclassName.string(),
+ indentStr, nclassName.c_str(),
getIndentSpace(indent+1));
for (a=0; a<NA; a++) {
@@ -2503,11 +2503,11 @@ static status_t writeLayoutClasses(
uint32_t typeSpecFlags = 0;
String16 name16(sym.name);
assets->getIncludedResources().identifierForName(
- name16.string(), name16.size(),
- attr16.string(), attr16.size(),
- package16.string(), package16.size(), &typeSpecFlags);
- //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
- // String8(attr16).string(), String8(name16).string(), typeSpecFlags);
+ name16.c_str(), name16.size(),
+ attr16.c_str(), attr16.size(),
+ package16.c_str(), package16.size(), &typeSpecFlags);
+ //printf("%s:%s/%s: 0x%08x\n", String8(package16).c_str(),
+ // String8(attr16).c_str(), String8(name16).c_str(), typeSpecFlags);
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
AnnotationProcessor ann;
@@ -2516,20 +2516,20 @@ static status_t writeLayoutClasses(
String8 cmt(comment);
ann.preprocessComment(cmt);
fprintf(fp, "%s <p>\n%s @attr description\n", indentStr, indentStr);
- fprintf(fp, "%s %s\n", indentStr, cmt.string());
+ fprintf(fp, "%s %s\n", indentStr, cmt.c_str());
} else {
fprintf(fp,
"%s <p>This symbol is the offset where the {@link %s.R.attr#%s}\n"
"%s attribute's value can be found in the {@link #%s} array.\n",
indentStr,
- getSymbolPackage(name8, assets, pub).string(),
- getSymbolName(name8).string(),
- indentStr, nclassName.string());
+ getSymbolPackage(name8, assets, pub).c_str(),
+ getSymbolName(name8).c_str(),
+ indentStr, nclassName.c_str());
}
if (typeComment.size() > 0) {
String8 cmt(typeComment);
ann.preprocessComment(cmt);
- fprintf(fp, "\n\n%s %s\n", indentStr, cmt.string());
+ fprintf(fp, "\n\n%s %s\n", indentStr, cmt.c_str());
}
if (comment.size() > 0) {
if (pub) {
@@ -2537,16 +2537,16 @@ static status_t writeLayoutClasses(
"%s <p>This corresponds to the global attribute\n"
"%s resource symbol {@link %s.R.attr#%s}.\n",
indentStr, indentStr,
- getSymbolPackage(name8, assets, true).string(),
- getSymbolName(name8).string());
+ getSymbolPackage(name8, assets, true).c_str(),
+ getSymbolName(name8).c_str());
} else {
fprintf(fp,
"%s <p>This is a private symbol.\n", indentStr);
}
}
fprintf(fp, "%s @attr name %s:%s\n", indentStr,
- getSymbolPackage(name8, assets, pub).string(),
- getSymbolName(name8).string());
+ getSymbolPackage(name8, assets, pub).c_str(),
+ getSymbolName(name8).c_str());
fprintf(fp, "%s*/\n", indentStr);
ann.printAnnotations(fp, indentStr);
@@ -2556,8 +2556,8 @@ static status_t writeLayoutClasses(
fprintf(fp,
id_format,
- indentStr, nclassName.string(),
- flattenSymbol(name8).string(), (int)pos);
+ indentStr, nclassName.c_str(),
+ flattenSymbol(name8).c_str(), (int)pos);
}
}
}
@@ -2598,12 +2598,12 @@ static status_t writeTextLayoutClasses(
String16 name16(sym.name);
uint32_t typeSpecFlags;
code = assets->getIncludedResources().identifierForName(
- name16.string(), name16.size(),
- attr16.string(), attr16.size(),
- package16.string(), package16.size(), &typeSpecFlags);
+ name16.c_str(), name16.size(),
+ attr16.c_str(), attr16.size(),
+ package16.c_str(), package16.size(), &typeSpecFlags);
if (code == 0) {
fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n",
- nclassName.string(), sym.name.string());
+ nclassName.c_str(), sym.name.c_str());
hasErrors = true;
}
isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
@@ -2615,7 +2615,7 @@ static status_t writeTextLayoutClasses(
NA = idents.size();
- fprintf(fp, "int[] styleable %s {", nclassName.string());
+ fprintf(fp, "int[] styleable %s {", nclassName.c_str());
for (a=0; a<NA; a++) {
if (a != 0) {
@@ -2645,17 +2645,17 @@ static status_t writeTextLayoutClasses(
uint32_t typeSpecFlags = 0;
String16 name16(sym.name);
assets->getIncludedResources().identifierForName(
- name16.string(), name16.size(),
- attr16.string(), attr16.size(),
- package16.string(), package16.size(), &typeSpecFlags);
- //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
- // String8(attr16).string(), String8(name16).string(), typeSpecFlags);
+ name16.c_str(), name16.size(),
+ attr16.c_str(), attr16.size(),
+ package16.c_str(), package16.size(), &typeSpecFlags);
+ //printf("%s:%s/%s: 0x%08x\n", String8(package16).c_str(),
+ // String8(attr16).c_str(), String8(name16).c_str(), typeSpecFlags);
//const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
fprintf(fp,
"int styleable %s_%s %d\n",
- nclassName.string(),
- flattenSymbol(name8).string(), (int)pos);
+ nclassName.c_str(),
+ flattenSymbol(name8).c_str(), (int)pos);
}
}
}
@@ -2670,7 +2670,7 @@ static status_t writeSymbolClass(
{
fprintf(fp, "%spublic %sfinal class %s {\n",
getIndentSpace(indent),
- indent != 0 ? "static " : "", className.string());
+ indent != 0 ? "static " : "", className.c_str());
indent++;
size_t i;
@@ -2699,7 +2699,7 @@ static status_t writeSymbolClass(
ann.preprocessComment(cmt);
fprintf(fp,
"%s/** %s\n",
- getIndentSpace(indent), cmt.string());
+ getIndentSpace(indent), cmt.c_str());
}
String16 typeComment(sym.typeComment);
if (typeComment.size() > 0) {
@@ -2708,10 +2708,10 @@ static status_t writeSymbolClass(
if (!haveComment) {
haveComment = true;
fprintf(fp,
- "%s/** %s\n", getIndentSpace(indent), cmt.string());
+ "%s/** %s\n", getIndentSpace(indent), cmt.c_str());
} else {
fprintf(fp,
- "%s %s\n", getIndentSpace(indent), cmt.string());
+ "%s %s\n", getIndentSpace(indent), cmt.c_str());
}
}
if (haveComment) {
@@ -2720,7 +2720,7 @@ static status_t writeSymbolClass(
ann.printAnnotations(fp, getIndentSpace(indent));
fprintf(fp, id_format,
getIndentSpace(indent),
- flattenSymbol(name8).string(), (int)sym.int32Val);
+ flattenSymbol(name8).c_str(), (int)sym.int32Val);
}
for (i=0; i<N; i++) {
@@ -2740,13 +2740,13 @@ static status_t writeSymbolClass(
fprintf(fp,
"%s/** %s\n"
"%s */\n",
- getIndentSpace(indent), cmt.string(),
+ getIndentSpace(indent), cmt.c_str(),
getIndentSpace(indent));
}
ann.printAnnotations(fp, getIndentSpace(indent));
fprintf(fp, "%spublic static final String %s=\"%s\";\n",
getIndentSpace(indent),
- flattenSymbol(name8).string(), sym.stringVal.string());
+ flattenSymbol(name8).c_str(), sym.stringVal.c_str());
}
sp<AaptSymbols> styleableSymbols;
@@ -2805,8 +2805,8 @@ static status_t writeTextSymbolClass(
String8 name8(sym.name);
fprintf(fp, "int %s %s 0x%08x\n",
- className.string(),
- flattenSymbol(name8).string(), (int)sym.int32Val);
+ className.c_str(),
+ flattenSymbol(name8).c_str(), (int)sym.int32Val);
}
N = symbols->getNestedSymbols().size();
@@ -2844,7 +2844,7 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
if (bundle->getMakePackageDirs()) {
const String8& pkg(package);
- const char* last = pkg.string();
+ const char* last = pkg.c_str();
const char* s = last-1;
do {
s++;
@@ -2852,9 +2852,9 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
String8 part(last, s-last);
dest.appendPath(part);
#ifdef _WIN32
- _mkdir(dest.string());
+ _mkdir(dest.c_str());
#else
- mkdir(dest.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+ mkdir(dest.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
#endif
last = s+1;
}
@@ -2862,14 +2862,14 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
}
dest.appendPath(className);
dest.append(".java");
- FILE* fp = fopen(dest.string(), "w+");
+ FILE* fp = fopen(dest.c_str(), "w+");
if (fp == NULL) {
fprintf(stderr, "ERROR: Unable to open class file %s: %s\n",
- dest.string(), strerror(errno));
+ dest.c_str(), strerror(errno));
return UNKNOWN_ERROR;
}
if (bundle->getVerbose()) {
- printf(" Writing symbols for class %s.\n", className.string());
+ printf(" Writing symbols for class %s.\n", className.c_str());
}
fprintf(fp,
@@ -2880,7 +2880,7 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
" * should not be modified by hand.\n"
" */\n"
"\n"
- "package %s;\n\n", package.string());
+ "package %s;\n\n", package.c_str());
status_t err = writeSymbolClass(fp, assets, includePrivate, symbols,
className, 0, bundle->getNonConstantId(), emitCallback);
@@ -2894,14 +2894,14 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
textDest.appendPath(className);
textDest.append(".txt");
- FILE* fp = fopen(textDest.string(), "w+");
+ FILE* fp = fopen(textDest.c_str(), "w+");
if (fp == NULL) {
fprintf(stderr, "ERROR: Unable to open text symbol file %s: %s\n",
- textDest.string(), strerror(errno));
+ textDest.c_str(), strerror(errno));
return UNKNOWN_ERROR;
}
if (bundle->getVerbose()) {
- printf(" Writing text symbols for class %s.\n", className.string());
+ printf(" Writing text symbols for class %s.\n", className.c_str());
}
status_t err = writeTextSymbolClass(fp, assets, includePrivate, symbols,
@@ -2919,8 +2919,8 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
String8 dependencyFile(bundle->getRClassDir());
dependencyFile.appendPath("R.java.d");
- FILE *fp = fopen(dependencyFile.string(), "a");
- fprintf(fp,"%s \\\n", dest.string());
+ FILE *fp = fopen(dependencyFile.c_str(), "a");
+ fprintf(fp,"%s \\\n", dest.c_str());
fclose(fp);
}
}
@@ -2956,7 +2956,7 @@ addProguardKeepRule(ProguardKeepSet* keep, const String8& inClassName,
// asdf --> package.asdf
// .asdf .a.b --> package.asdf package.a.b
// asdf.adsf --> asdf.asdf
- const char* p = className.string();
+ const char* p = className.c_str();
const char* q = strchr(p, '.');
if (p == q) {
className = pkg;
@@ -3023,7 +3023,7 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass
if (assGroup->getFiles().size() != 1) {
fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
- assGroup->getFiles().valueAt(0)->getPrintableSource().string());
+ assGroup->getFiles().valueAt(0)->getPrintableSource().c_str());
}
assFile = assGroup->getFiles().valueAt(0);
@@ -3048,7 +3048,7 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass
}
depth++;
String8 tag(tree.getElementName(&len));
- // printf("Depth %d tag %s\n", depth, tag.string());
+ // printf("Depth %d tag %s\n", depth, tag.c_str());
bool keepTag = false;
if (depth == 1) {
if (tag != "manifest") {
@@ -3065,7 +3065,7 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass
"http://schemas.android.com/apk/res/android",
"backupAgent", &error);
if (agent.length() > 0) {
- addProguardKeepRule(keep, agent, pkg.string(),
+ addProguardKeepRule(keep, agent, pkg.c_str(),
assFile->getPrintableSource(), tree.getLineNumber());
}
@@ -3073,7 +3073,7 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass
defaultProcess = AaptXml::getAttribute(tree,
"http://schemas.android.com/apk/res/android", "process", &error);
if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
+ fprintf(stderr, "ERROR: %s\n", error.c_str());
return -1;
}
}
@@ -3089,7 +3089,7 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass
String8 componentProcess = AaptXml::getAttribute(tree,
"http://schemas.android.com/apk/res/android", "process", &error);
if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
+ fprintf(stderr, "ERROR: %s\n", error.c_str());
return -1;
}
@@ -3103,14 +3103,14 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass
String8 name = AaptXml::getAttribute(tree,
"http://schemas.android.com/apk/res/android", "name", &error);
if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
+ fprintf(stderr, "ERROR: %s\n", error.c_str());
return -1;
}
keepTag = name.length() > 0;
if (keepTag) {
- addProguardKeepRule(keep, name, pkg.string(),
+ addProguardKeepRule(keep, name, pkg.c_str(),
assFile->getPrintableSource(), tree.getLineNumber());
}
}
@@ -3170,7 +3170,7 @@ writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
String8 tag(tree.getElementName(&len));
// If there is no '.', we'll assume that it's one of the built in names.
- if (strchr(tag.string(), '.')) {
+ if (strchr(tag.c_str(), '.')) {
addProguardKeepRule(keep, tag, NULL,
layoutFile->getPrintableSource(), tree.getLineNumber());
} else if (tagAttrPairs != NULL) {
@@ -3183,8 +3183,8 @@ writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
ssize_t attrIndex = tree.indexOfAttribute(nsAttr.ns, nsAttr.attr);
if (attrIndex < 0) {
// fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n",
- // layoutFile->getPrintableSource().string(), tree.getLineNumber(),
- // tag.string(), nsAttr.ns, nsAttr.attr);
+ // layoutFile->getPrintableSource().c_str(), tree.getLineNumber(),
+ // tag.c_str(), nsAttr.ns, nsAttr.attr);
} else {
size_t len;
addProguardKeepRule(keep,
@@ -3242,7 +3242,7 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
// tag:attribute pairs that should be checked in transition files.
KeyedVector<String8, Vector<NamespaceAttributePair> > kTransitionTagAttrPairs;
- addTagAttrPair(&kTransitionTagAttrPairs, kTransition.string(), NULL, kClass);
+ addTagAttrPair(&kTransitionTagAttrPairs, kTransition.c_str(), NULL, kClass);
addTagAttrPair(&kTransitionTagAttrPairs, "pathMotion", NULL, kClass);
const Vector<sp<AaptDir> >& dirs = assets->resDirs();
@@ -3252,16 +3252,16 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
const String8& dirName = d->getLeaf();
Vector<String8> startTags;
const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
- if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
+ if ((dirName == String8("layout")) || (strncmp(dirName.c_str(), "layout-", 7) == 0)) {
tagAttrPairs = &kLayoutTagAttrPairs;
- } else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
+ } else if ((dirName == String8("xml")) || (strncmp(dirName.c_str(), "xml-", 4) == 0)) {
startTags.add(String8("PreferenceScreen"));
startTags.add(String8("preference-headers"));
tagAttrPairs = &kXmlTagAttrPairs;
- } else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
+ } else if ((dirName == String8("menu")) || (strncmp(dirName.c_str(), "menu-", 5) == 0)) {
startTags.add(String8("menu"));
tagAttrPairs = NULL;
- } else if (dirName == kTransition || (strncmp(dirName.string(), kTransitionPrefix.string(),
+ } else if (dirName == kTransition || (strncmp(dirName.c_str(), kTransitionPrefix.c_str(),
kTransitionPrefix.size()) == 0)) {
tagAttrPairs = &kTransitionTagAttrPairs;
} else {
@@ -3307,9 +3307,9 @@ writeProguardSpec(const char* filename, const ProguardKeepSet& keep, status_t er
const SortedVector<String8>& locations = rules.valueAt(i);
const size_t M = locations.size();
for (size_t j=0; j<M; j++) {
- fprintf(fp, "# %s\n", locations.itemAt(j).string());
+ fprintf(fp, "# %s\n", locations.itemAt(j).c_str());
}
- fprintf(fp, "%s\n\n", rules.keyAt(i).string());
+ fprintf(fp, "%s\n\n", rules.keyAt(i).c_str());
}
fclose(fp);
@@ -3366,7 +3366,7 @@ status_t writePathsToFile(const sp<FilePathStore>& files, FILE* fp)
status_t deps = -1;
for (size_t file_i = 0; file_i < files->size(); ++file_i) {
// Add the full file path to the dependency file
- fprintf(fp, "%s \\\n", files->itemAt(file_i).string());
+ fprintf(fp, "%s \\\n", files->itemAt(file_i).c_str());
deps++;
}
return deps;
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index ed06f605eaeb..cc8dce7e9f3e 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -32,7 +32,7 @@ WeakResourceFilter::parse(const String8& str)
// only specify locale in the standard 'en_US' format.
val.writeTo(&entry.first);
} else if (!AaptConfig::parse(part, &entry.first)) {
- fprintf(stderr, "Invalid configuration: %s\n", part.string());
+ fprintf(stderr, "Invalid configuration: %s\n", part.c_str());
return UNKNOWN_ERROR;
}
@@ -43,7 +43,7 @@ WeakResourceFilter::parse(const String8& str)
// Ignore any densities. Those are best handled in --preferred-density
if ((entry.second & ResTable_config::CONFIG_DENSITY) != 0) {
- fprintf(stderr, "warning: ignoring flag -c %s. Use --preferred-density instead.\n", entry.first.toString().string());
+ fprintf(stderr, "warning: ignoring flag -c %s. Use --preferred-density instead.\n", entry.first.toString().c_str());
entry.first.density = 0;
entry.second &= ~ResTable_config::CONFIG_DENSITY;
}
@@ -148,7 +148,7 @@ StrongResourceFilter::parse(const String8& str) {
mConfigs.clear();
for (size_t i = 0; i < configStrs.size(); i++) {
if (!AaptConfig::parse(configStrs[i], &config)) {
- fprintf(stderr, "Invalid configuration: %s\n", configStrs[i].string());
+ fprintf(stderr, "Invalid configuration: %s\n", configStrs[i].c_str());
return UNKNOWN_ERROR;
}
mConfigs.insert(config);
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index 8835fb0130a3..1c7788d70053 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -37,7 +37,7 @@ static inline uint32_t hashround(uint32_t hash, int c) {
static uint32_t hash(const android::String16& hashableString) {
uint32_t hash = 5381;
- const char16_t* str = hashableString.string();
+ const char16_t* str = hashableString.c_str();
while (int c = *str++) hash = hashround(hash, c);
return hash;
}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 4e597fb3b30a..23440074a326 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -361,10 +361,10 @@ static status_t compileAttribute(const sp<AaptFile>& in,
ssize_t typeIdx = block.indexOfAttribute(NULL, "format");
if (typeIdx >= 0) {
String16 typeStr = String16(block.getAttributeStringValue(typeIdx, &len));
- attr.type = parse_flags(typeStr.string(), typeStr.size(), gFormatFlags);
+ attr.type = parse_flags(typeStr.c_str(), typeStr.size(), gFormatFlags);
if (attr.type == 0) {
attr.sourcePos.error("Tag <attr> 'format' attribute value \"%s\" not valid\n",
- String8(typeStr).string());
+ String8(typeStr).c_str());
attr.hasErrors = true;
}
attr.createIfNeeded(outTable);
@@ -374,14 +374,14 @@ static status_t compileAttribute(const sp<AaptFile>& in,
attr.createIfNeeded(outTable);
}
- //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).string(), attr.type);
+ //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).c_str(), attr.type);
ssize_t minIdx = block.indexOfAttribute(NULL, "min");
if (minIdx >= 0) {
String16 val = String16(block.getAttributeStringValue(minIdx, &len));
- if (!ResTable::stringToInt(val.string(), val.size(), NULL)) {
+ if (!ResTable::stringToInt(val.c_str(), val.size(), NULL)) {
attr.sourcePos.error("Tag <attr> 'min' attribute must be a number, not \"%s\"\n",
- String8(val).string());
+ String8(val).c_str());
attr.hasErrors = true;
}
attr.createIfNeeded(outTable);
@@ -397,9 +397,9 @@ static status_t compileAttribute(const sp<AaptFile>& in,
ssize_t maxIdx = block.indexOfAttribute(NULL, "max");
if (maxIdx >= 0) {
String16 val = String16(block.getAttributeStringValue(maxIdx, &len));
- if (!ResTable::stringToInt(val.string(), val.size(), NULL)) {
+ if (!ResTable::stringToInt(val.c_str(), val.size(), NULL)) {
attr.sourcePos.error("Tag <attr> 'max' attribute must be a number, not \"%s\"\n",
- String8(val).string());
+ String8(val).c_str());
attr.hasErrors = true;
}
attr.createIfNeeded(outTable);
@@ -422,7 +422,7 @@ static status_t compileAttribute(const sp<AaptFile>& in,
uint32_t l10n_required = parse_flags(str, len, l10nRequiredFlags, &error);
if (error) {
attr.sourcePos.error("Tag <attr> 'localization' attribute value \"%s\" not valid\n",
- String8(str).string());
+ String8(str).c_str());
attr.hasErrors = true;
}
attr.createIfNeeded(outTable);
@@ -442,14 +442,14 @@ static status_t compileAttribute(const sp<AaptFile>& in,
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
uint32_t localType = 0;
- if (strcmp16(block.getElementName(&len), enum16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), enum16.c_str()) == 0) {
localType = ResTable_map::TYPE_ENUM;
- } else if (strcmp16(block.getElementName(&len), flag16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), flag16.c_str()) == 0) {
localType = ResTable_map::TYPE_FLAGS;
} else {
SourcePos(in->getPrintableSource(), block.getLineNumber())
.error("Tag <%s> can not appear inside <attr>, only <enum> or <flag>\n",
- String8(block.getElementName(&len)).string());
+ String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
@@ -505,11 +505,11 @@ static status_t compileAttribute(const sp<AaptFile>& in,
.error("A 'value' attribute is required for <enum> or <flag>\n");
attr.hasErrors = true;
}
- if (!attr.hasErrors && !ResTable::stringToInt(value.string(), value.size(), NULL)) {
+ if (!attr.hasErrors && !ResTable::stringToInt(value.c_str(), value.size(), NULL)) {
SourcePos(in->getPrintableSource(), block.getLineNumber())
.error("Tag <enum> or <flag> 'value' attribute must be a number,"
" not \"%s\"\n",
- String8(value).string());
+ String8(value).c_str());
attr.hasErrors = true;
}
@@ -546,21 +546,21 @@ static status_t compileAttribute(const sp<AaptFile>& in,
}
}
} else if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), attr16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), attr16.c_str()) == 0) {
break;
}
if ((attr.type&ResTable_map::TYPE_ENUM) != 0) {
- if (strcmp16(block.getElementName(&len), enum16.string()) != 0) {
+ if (strcmp16(block.getElementName(&len), enum16.c_str()) != 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber())
.error("Found tag </%s> where </enum> is expected\n",
- String8(block.getElementName(&len)).string());
+ String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
} else {
- if (strcmp16(block.getElementName(&len), flag16.string()) != 0) {
+ if (strcmp16(block.getElementName(&len), flag16.c_str()) != 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber())
.error("Found tag </%s> where </flag> is expected\n",
- String8(block.getElementName(&len)).string());
+ String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
}
@@ -606,7 +606,7 @@ status_t parseAndAddBag(Bundle* bundle,
String16 str;
Vector<StringPool::entry_style_span> spans;
- err = parseStyledString(bundle, in->getPrintableSource().string(),
+ err = parseStyledString(bundle, in->getPrintableSource().c_str(),
block, item16, &str, &spans, isFormatted,
pseudolocalize);
if (err != NO_ERROR) {
@@ -619,10 +619,10 @@ status_t parseAndAddBag(Bundle* bundle,
config.language[0], config.language[1],
config.country[0], config.country[1],
config.orientation, config.density,
- String8(parentIdent).string(),
- String8(ident).string(),
- String8(itemIdent).string(),
- String8(str).string());
+ String8(parentIdent).c_str(),
+ String8(ident).c_str(),
+ String8(itemIdent).c_str(),
+ String8(str).c_str());
}
err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()),
@@ -636,8 +636,8 @@ status_t parseAndAddBag(Bundle* bundle,
* haystack, false otherwise.
*/
bool isInProductList(const String16& needle, const String16& haystack) {
- const char16_t *needle2 = needle.string();
- const char16_t *haystack2 = haystack.string();
+ const char16_t *needle2 = needle.c_str();
+ const char16_t *haystack2 = haystack.c_str();
size_t needlesize = needle.size();
while (*haystack2 != '\0') {
@@ -703,7 +703,7 @@ status_t parseAndAddEntry(Bundle* bundle,
String16 str;
Vector<StringPool::entry_style_span> spans;
- err = parseStyledString(bundle, in->getPrintableSource().string(), block,
+ err = parseStyledString(bundle, in->getPrintableSource().c_str(), block,
curTag, &str, curIsStyled ? &spans : NULL,
isFormatted, pseudolocalize);
@@ -730,7 +730,7 @@ status_t parseAndAddEntry(Bundle* bundle,
*/
if (bundleProduct[0] == '\0') {
- if (strcmp16(String16("default").string(), product.string()) != 0) {
+ if (strcmp16(String16("default").c_str(), product.c_str()) != 0) {
/*
* This string has a product other than 'default'. Do not add it,
* but record it so that if we do not see the same string with
@@ -750,7 +750,7 @@ status_t parseAndAddEntry(Bundle* bundle,
if (isInProductList(product, String16(bundleProduct))) {
;
- } else if (strcmp16(String16("default").string(), product.string()) == 0 &&
+ } else if (strcmp16(String16("default").c_str(), product.c_str()) == 0 &&
!outTable->hasBagOrEntry(myPackage, curType, ident, config)) {
;
} else {
@@ -764,7 +764,7 @@ status_t parseAndAddEntry(Bundle* bundle,
config.language[0], config.language[1],
config.country[0], config.country[1],
config.orientation, config.density,
- String8(ident).string(), String8(str).string());
+ String8(ident).c_str(), String8(str).c_str());
}
err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
@@ -847,7 +847,7 @@ status_t compileResourceFile(Bundle* bundle,
bool hasErrors = false;
bool fileIsTranslatable = true;
- if (strstr(in->getPrintableSource().string(), "donottranslate") != NULL) {
+ if (strstr(in->getPrintableSource().c_str(), "donottranslate") != NULL) {
fileIsTranslatable = false;
}
@@ -869,9 +869,9 @@ status_t compileResourceFile(Bundle* bundle,
"No start tag found\n");
return UNKNOWN_ERROR;
}
- if (strcmp16(block.getElementName(&len), resources16.string()) != 0) {
+ if (strcmp16(block.getElementName(&len), resources16.c_str()) != 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
- "Invalid start tag %s\n", String8(block.getElementName(&len)).string());
+ "Invalid start tag %s\n", String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
@@ -900,7 +900,7 @@ status_t compileResourceFile(Bundle* bundle,
SourcePos(in->getPrintableSource(), 0).warning(
"Resource file %s is skipped as pseudolocalization"
" was done automatically.",
- in->getPrintableSource().string());
+ in->getPrintableSource().c_str());
return NO_ERROR;
}
@@ -917,29 +917,29 @@ status_t compileResourceFile(Bundle* bundle,
bool curIsFormatted = fileIsTranslatable;
bool localHasErrors = false;
- if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
while ((code=block.next()) != ResXMLTree::END_DOCUMENT
&& code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
while ((code=block.next()) != ResXMLTree::END_DOCUMENT
&& code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), public16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), public16.c_str()) == 0) {
SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
String16 type;
@@ -965,7 +965,7 @@ status_t compileResourceFile(Bundle* bundle,
Res_value identValue;
if (!ResTable::stringToInt(identStr, len, &identValue)) {
srcPos.error("Given 'id' attribute is not an integer: %s\n",
- String8(block.getAttributeStringValue(identIdx, &len)).string());
+ String8(block.getAttributeStringValue(identIdx, &len)).c_str());
hasErrors = localHasErrors = true;
} else {
ident = identValue.data;
@@ -1004,14 +1004,14 @@ status_t compileResourceFile(Bundle* bundle,
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), public16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), public16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), public_padding16.c_str()) == 0) {
SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
String16 type;
@@ -1037,7 +1037,7 @@ status_t compileResourceFile(Bundle* bundle,
Res_value startValue;
if (!ResTable::stringToInt(startStr, len, &startValue)) {
srcPos.error("Given 'start' attribute is not an integer: %s\n",
- String8(block.getAttributeStringValue(startIdx, &len)).string());
+ String8(block.getAttributeStringValue(startIdx, &len)).c_str());
hasErrors = localHasErrors = true;
} else {
start = startValue.data;
@@ -1057,7 +1057,7 @@ status_t compileResourceFile(Bundle* bundle,
Res_value endValue;
if (!ResTable::stringToInt(endStr, len, &endValue)) {
srcPos.error("Given 'end' attribute is not an integer: %s\n",
- String8(block.getAttributeStringValue(endIdx, &len)).string());
+ String8(block.getAttributeStringValue(endIdx, &len)).c_str());
hasErrors = localHasErrors = true;
} else {
end = endValue.data;
@@ -1114,14 +1114,14 @@ status_t compileResourceFile(Bundle* bundle,
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), public_padding16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), private_symbols16.c_str()) == 0) {
String16 pkg;
ssize_t pkgIdx = block.indexOfAttribute(NULL, "package");
if (pkgIdx < 0) {
@@ -1144,14 +1144,14 @@ status_t compileResourceFile(Bundle* bundle,
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), private_symbols16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), java_symbol16.c_str()) == 0) {
SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
String16 type;
@@ -1186,7 +1186,7 @@ status_t compileResourceFile(Bundle* bundle,
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), java_symbol16.c_str()) == 0) {
break;
}
}
@@ -1194,7 +1194,7 @@ status_t compileResourceFile(Bundle* bundle,
continue;
- } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), add_resource16.c_str()) == 0) {
SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
String16 typeName;
@@ -1217,14 +1217,14 @@ status_t compileResourceFile(Bundle* bundle,
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), add_resource16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), declare_styleable16.c_str()) == 0) {
SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
String16 ident;
@@ -1258,30 +1258,30 @@ status_t compileResourceFile(Bundle* bundle,
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
- if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
while ((code=block.next()) != ResXMLTree::END_DOCUMENT
&& code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
while ((code=block.next()) != ResXMLTree::END_DOCUMENT
&& code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
break;
}
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), attr16.string()) != 0) {
+ } else if (strcmp16(block.getElementName(&len), attr16.c_str()) != 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Tag <%s> can not appear inside <declare-styleable>, only <attr>\n",
- String8(block.getElementName(&len)).string());
+ String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
@@ -1297,30 +1297,30 @@ status_t compileResourceFile(Bundle* bundle,
SourcePos srcPos(String8(in->getPrintableSource()), block.getLineNumber());
symbols->addSymbol(String8(itemIdent), 0, srcPos);
symbols->appendComment(String8(itemIdent), comment, srcPos);
- //printf("Attribute %s comment: %s\n", String8(itemIdent).string(),
- // String8(comment).string());
+ //printf("Attribute %s comment: %s\n", String8(itemIdent).c_str(),
+ // String8(comment).c_str());
}
} else if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
+ if (strcmp16(block.getElementName(&len), declare_styleable16.c_str()) == 0) {
break;
}
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Found tag </%s> where </attr> is expected\n",
- String8(block.getElementName(&len)).string());
+ String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
}
continue;
- } else if (strcmp16(block.getElementName(&len), attr16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), attr16.c_str()) == 0) {
err = compileAttribute(in, block, myPackage, outTable, NULL);
if (err != NO_ERROR) {
hasErrors = true;
}
continue;
- } else if (strcmp16(block.getElementName(&len), item16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), item16.c_str()) == 0) {
curTag = &item16;
ssize_t attri = block.indexOfAttribute(NULL, "type");
if (attri >= 0) {
@@ -1333,12 +1333,12 @@ status_t compileResourceFile(Bundle* bundle,
if (formatIdx >= 0) {
String16 formatStr = String16(block.getAttributeStringValue(
formatIdx, &len));
- curFormat = parse_flags(formatStr.string(), formatStr.size(),
+ curFormat = parse_flags(formatStr.c_str(), formatStr.size(),
gFormatFlags);
if (curFormat == 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Tag <item> 'format' attribute value \"%s\" not valid\n",
- String8(formatStr).string());
+ String8(formatStr).c_str());
hasErrors = localHasErrors = true;
}
}
@@ -1348,7 +1348,7 @@ status_t compileResourceFile(Bundle* bundle,
hasErrors = localHasErrors = true;
}
curIsStyled = true;
- } else if (strcmp16(block.getElementName(&len), string16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), string16.c_str()) == 0) {
// Note the existence and locale of every string we process
char rawLocale[RESTABLE_MAX_LOCALE_LEN];
curParams.getBcp47Locale(rawLocale);
@@ -1361,11 +1361,11 @@ status_t compileResourceFile(Bundle* bundle,
for (size_t i = 0; i < n; i++) {
size_t length;
const char16_t* attr = block.getAttributeName(i, &length);
- if (strcmp16(attr, name16.string()) == 0) {
+ if (strcmp16(attr, name16.c_str()) == 0) {
name.setTo(block.getAttributeStringValue(i, &length));
- } else if (strcmp16(attr, translatable16.string()) == 0) {
+ } else if (strcmp16(attr, translatable16.c_str()) == 0) {
translatable.setTo(block.getAttributeStringValue(i, &length));
- } else if (strcmp16(attr, formatted16.string()) == 0) {
+ } else if (strcmp16(attr, formatted16.c_str()) == 0) {
formatted.setTo(block.getAttributeStringValue(i, &length));
}
}
@@ -1380,8 +1380,8 @@ status_t compileResourceFile(Bundle* bundle,
if (locale.size() > 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
"string '%s' marked untranslatable but exists in locale '%s'\n",
- String8(name).string(),
- locale.string());
+ String8(name).c_str(),
+ locale.c_str());
// hasErrors = localHasErrors = true;
} else {
// Intentionally empty block:
@@ -1407,31 +1407,31 @@ status_t compileResourceFile(Bundle* bundle,
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
curIsStyled = true;
curIsPseudolocalizable = fileIsTranslatable && (translatable != false16);
- } else if (strcmp16(block.getElementName(&len), drawable16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), drawable16.c_str()) == 0) {
curTag = &drawable16;
curType = drawable16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
- } else if (strcmp16(block.getElementName(&len), color16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), color16.c_str()) == 0) {
curTag = &color16;
curType = color16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
- } else if (strcmp16(block.getElementName(&len), bool16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), bool16.c_str()) == 0) {
curTag = &bool16;
curType = bool16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_BOOLEAN;
- } else if (strcmp16(block.getElementName(&len), integer16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), integer16.c_str()) == 0) {
curTag = &integer16;
curType = integer16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
- } else if (strcmp16(block.getElementName(&len), dimen16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), dimen16.c_str()) == 0) {
curTag = &dimen16;
curType = dimen16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_DIMENSION;
- } else if (strcmp16(block.getElementName(&len), fraction16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), fraction16.c_str()) == 0) {
curTag = &fraction16;
curType = fraction16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_FRACTION;
- } else if (strcmp16(block.getElementName(&len), bag16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), bag16.c_str()) == 0) {
curTag = &bag16;
curIsBag = true;
ssize_t attri = block.indexOfAttribute(NULL, "type");
@@ -1442,16 +1442,16 @@ status_t compileResourceFile(Bundle* bundle,
"A 'type' attribute is required for <bag>\n");
hasErrors = localHasErrors = true;
}
- } else if (strcmp16(block.getElementName(&len), style16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), style16.c_str()) == 0) {
curTag = &style16;
curType = style16;
curIsBag = true;
- } else if (strcmp16(block.getElementName(&len), plurals16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), plurals16.c_str()) == 0) {
curTag = &plurals16;
curType = plurals16;
curIsBag = true;
curIsPseudolocalizable = fileIsTranslatable;
- } else if (strcmp16(block.getElementName(&len), array16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), array16.c_str()) == 0) {
curTag = &array16;
curType = array16;
curIsBag = true;
@@ -1460,16 +1460,16 @@ status_t compileResourceFile(Bundle* bundle,
if (formatIdx >= 0) {
String16 formatStr = String16(block.getAttributeStringValue(
formatIdx, &len));
- curFormat = parse_flags(formatStr.string(), formatStr.size(),
+ curFormat = parse_flags(formatStr.c_str(), formatStr.size(),
gFormatFlags);
if (curFormat == 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Tag <array> 'format' attribute value \"%s\" not valid\n",
- String8(formatStr).string());
+ String8(formatStr).c_str());
hasErrors = localHasErrors = true;
}
}
- } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), string_array16.c_str()) == 0) {
// Check whether these strings need valid formats.
// (simplified form of what string16 does above)
bool isTranslatable = false;
@@ -1480,14 +1480,14 @@ status_t compileResourceFile(Bundle* bundle,
for (size_t i = 0; i < n; i++) {
size_t length;
const char16_t* attr = block.getAttributeName(i, &length);
- if (strcmp16(attr, formatted16.string()) == 0) {
+ if (strcmp16(attr, formatted16.c_str()) == 0) {
const char16_t* value = block.getAttributeStringValue(i, &length);
- if (strcmp16(value, false16.string()) == 0) {
+ if (strcmp16(value, false16.c_str()) == 0) {
curIsFormatted = false;
}
- } else if (strcmp16(attr, translatable16.string()) == 0) {
+ } else if (strcmp16(attr, translatable16.c_str()) == 0) {
const char16_t* value = block.getAttributeStringValue(i, &length);
- if (strcmp16(value, false16.string()) == 0) {
+ if (strcmp16(value, false16.c_str()) == 0) {
isTranslatable = false;
}
}
@@ -1499,7 +1499,7 @@ status_t compileResourceFile(Bundle* bundle,
curIsBag = true;
curIsBagReplaceOnOverwrite = true;
curIsPseudolocalizable = isTranslatable && fileIsTranslatable;
- } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) {
+ } else if (strcmp16(block.getElementName(&len), integer_array16.c_str()) == 0) {
curTag = &integer_array16;
curType = array16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
@@ -1508,7 +1508,7 @@ status_t compileResourceFile(Bundle* bundle,
} else {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Found tag %s where item is expected\n",
- String8(block.getElementName(&len)).string());
+ String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
@@ -1519,7 +1519,7 @@ status_t compileResourceFile(Bundle* bundle,
} else {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"A 'name' attribute is required for <%s>\n",
- String8(*curTag).string());
+ String8(*curTag).c_str());
hasErrors = localHasErrors = true;
}
@@ -1560,11 +1560,11 @@ status_t compileResourceFile(Bundle* bundle,
&& code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
- if (strcmp16(block.getElementName(&len), item16.string()) != 0) {
+ if (strcmp16(block.getElementName(&len), item16.c_str()) != 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Tag <%s> can not appear inside <%s>, only <item>\n",
- String8(block.getElementName(&len)).string(),
- String8(*curTag).string());
+ String8(block.getElementName(&len)).c_str(),
+ String8(*curTag).c_str());
return UNKNOWN_ERROR;
}
@@ -1647,11 +1647,11 @@ status_t compileResourceFile(Bundle* bundle,
hasErrors = localHasErrors = true;
}
} else if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), curTag->string()) != 0) {
+ if (strcmp16(block.getElementName(&len), curTag->c_str()) != 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Found tag </%s> where </%s> is expected\n",
- String8(block.getElementName(&len)).string(),
- String8(*curTag).string());
+ String8(block.getElementName(&len)).c_str(),
+ String8(*curTag).c_str());
return UNKNOWN_ERROR;
}
break;
@@ -1700,9 +1700,9 @@ status_t compileResourceFile(Bundle* bundle,
#if 0
if (comment.size() > 0) {
- printf("Comment for @%s:%s/%s: %s\n", String8(myPackage).string(),
- String8(curType).string(), String8(ident).string(),
- String8(comment).string());
+ printf("Comment for @%s:%s/%s: %s\n", String8(myPackage).c_str(),
+ String8(curType).c_str(), String8(ident).c_str(),
+ String8(comment).c_str());
}
#endif
if (!localHasErrors) {
@@ -1710,9 +1710,9 @@ status_t compileResourceFile(Bundle* bundle,
}
}
else if (code == ResXMLTree::END_TAG) {
- if (strcmp16(block.getElementName(&len), resources16.string()) != 0) {
+ if (strcmp16(block.getElementName(&len), resources16.c_str()) != 0) {
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
- "Unexpected end tag %s\n", String8(block.getElementName(&len)).string());
+ "Unexpected end tag %s\n", String8(block.getElementName(&len)).c_str());
return UNKNOWN_ERROR;
}
}
@@ -1724,7 +1724,7 @@ status_t compileResourceFile(Bundle* bundle,
}
SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
"Found text \"%s\" where item tag is expected\n",
- String8(block.getText(&len)).string());
+ String8(block.getText(&len)).c_str());
return UNKNOWN_ERROR;
}
}
@@ -1740,13 +1740,13 @@ status_t compileResourceFile(Bundle* bundle,
const char* bundleProduct =
(bundle->getProduct() == NULL) ? "" : bundle->getProduct();
fprintf(stderr, "In resource file %s: %s\n",
- in->getPrintableSource().string(),
- curParams.toString().string());
+ in->getPrintableSource().c_str(),
+ curParams.toString().c_str());
fprintf(stderr, "\t%s '%s' does not match product %s.\n"
"\tYou may have forgotten to include a 'default' product variant"
" of the resource.\n",
- String8(p.type).string(), String8(p.ident).string(),
+ String8(p.type).c_str(), String8(p.ident).c_str(),
bundleProduct[0] == 0 ? "default" : bundleProduct);
return UNKNOWN_ERROR;
}
@@ -1816,7 +1816,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets
AssetManager featureAssetManager;
if (!featureAssetManager.addAssetPath(featureAfter, NULL)) {
fprintf(stderr, "ERROR: Feature package '%s' not found.\n",
- featureAfter.string());
+ featureAfter.c_str());
return UNKNOWN_ERROR;
}
@@ -1835,13 +1835,13 @@ status_t ResourceTable::addPublic(const SourcePos& sourcePos,
const uint32_t ident)
{
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size());
+ .identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size());
if (rid != 0) {
sourcePos.error("Error declaring public resource %s/%s for included package %s\n",
- String8(type).string(), String8(name).string(),
- String8(package).string());
+ String8(type).c_str(), String8(name).c_str(),
+ String8(package).c_str());
return UNKNOWN_ERROR;
}
@@ -1864,12 +1864,12 @@ status_t ResourceTable::addEntry(const SourcePos& sourcePos,
const bool overwrite)
{
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size());
+ .identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size());
if (rid != 0) {
sourcePos.error("Resource entry %s/%s is already defined in package %s.",
- String8(type).string(), String8(name).string(), String8(package).string());
+ String8(type).c_str(), String8(name).c_str(), String8(package).c_str());
return UNKNOWN_ERROR;
}
@@ -1899,12 +1899,12 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
// Check for adding entries in other packages... for now we do
// nothing. We need to do the right thing here to support skinning.
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size());
+ .identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size());
if (rid != 0) {
sourcePos.error("Resource entry %s/%s is already defined in package %s.",
- String8(type).string(), String8(name).string(), String8(package).string());
+ String8(type).c_str(), String8(name).c_str(), String8(package).c_str());
return UNKNOWN_ERROR;
}
@@ -1921,7 +1921,7 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
}
if (!canAdd) {
sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n",
- String8(name).string());
+ String8(name).c_str());
return UNKNOWN_ERROR;
}
}
@@ -1959,9 +1959,9 @@ status_t ResourceTable::addBag(const SourcePos& sourcePos,
// Check for adding entries in other packages... for now we do
// nothing. We need to do the right thing here to support skinning.
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size());
+ .identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size());
if (rid != 0) {
return NO_ERROR;
}
@@ -1969,7 +1969,7 @@ status_t ResourceTable::addBag(const SourcePos& sourcePos,
#if 0
if (name == String16("left")) {
printf("Adding bag left: file=%s, line=%d, type=%s\n",
- sourcePos.file.striing(), sourcePos.line, String8(type).string());
+ sourcePos.file.striing(), sourcePos.line, String8(type).c_str());
}
#endif
sp<Entry> e = getEntry(package, type, name, sourcePos, replace, params);
@@ -1996,9 +1996,9 @@ bool ResourceTable::hasBagOrEntry(const String16& package,
{
// First look for this in the included resources...
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size());
+ .identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size());
if (rid != 0) {
return true;
}
@@ -2022,9 +2022,9 @@ bool ResourceTable::hasBagOrEntry(const String16& package,
{
// First look for this in the included resources...
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size());
+ .identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size());
if (rid != 0) {
return true;
}
@@ -2051,7 +2051,7 @@ bool ResourceTable::hasBagOrEntry(const String16& ref,
const String16* defPackage)
{
String16 package, type, name;
- if (!ResTable::expandResourceRef(ref.string(), ref.size(), &package, &type, &name,
+ if (!ResTable::expandResourceRef(ref.c_str(), ref.size(), &package, &type, &name,
defType, defPackage ? defPackage:&mAssetsPackage, NULL)) {
return false;
}
@@ -2115,17 +2115,17 @@ bool ResourceTable::makeAttribute(const String16& package,
// First look for this in the included resources...
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- attr16.string(), attr16.size(),
- package.string(), package.size());
+ .identifierForName(name.c_str(), name.size(),
+ attr16.c_str(), attr16.size(),
+ package.c_str(), package.size());
if (rid != 0) {
- source.error("Attribute \"%s\" has already been defined", String8(name).string());
+ source.error("Attribute \"%s\" has already been defined", String8(name).c_str());
return false;
}
sp<ResourceTable::Entry> entry = getEntry(package, attr16, name, source, false);
if (entry == NULL) {
- source.error("Failed to create entry attr/%s", String8(name).string());
+ source.error("Failed to create entry attr/%s", String8(name).c_str());
return false;
}
@@ -2146,7 +2146,7 @@ bool ResourceTable::makeAttribute(const String16& package,
formatItem.value != formatValue16) {
source.error("Attribute \"%s\" already defined with incompatible format.\n"
"%s:%d: Original attribute defined here.",
- String8(name).string(), formatItem.sourcePos.file.string(),
+ String8(name).c_str(), formatItem.sourcePos.file.c_str(),
formatItem.sourcePos.line);
return false;
}
@@ -2207,9 +2207,9 @@ uint32_t ResourceTable::getResId(const String16& package,
// First look for this in the included resources...
uint32_t specFlags = 0;
uint32_t rid = mAssets->getIncludedResources()
- .identifierForName(name.string(), name.size(),
- type.string(), type.size(),
- package.string(), package.size(),
+ .identifierForName(name.c_str(), name.size(),
+ type.c_str(), type.size(),
+ package.c_str(), package.size(),
&specFlags);
if (rid != 0) {
if (onlyPublic && (specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
@@ -2253,27 +2253,27 @@ uint32_t ResourceTable::getResId(const String16& ref,
String16 package, type, name;
bool refOnlyPublic = true;
if (!ResTable::expandResourceRef(
- ref.string(), ref.size(), &package, &type, &name,
+ ref.c_str(), ref.size(), &package, &type, &name,
defType, defPackage ? defPackage:&mAssetsPackage,
outErrorMsg, &refOnlyPublic)) {
if (kIsDebug) {
- printf("Expanding resource: ref=%s\n", String8(ref).string());
+ printf("Expanding resource: ref=%s\n", String8(ref).c_str());
printf("Expanding resource: defType=%s\n",
- defType ? String8(*defType).string() : "NULL");
+ defType ? String8(*defType).c_str() : "NULL");
printf("Expanding resource: defPackage=%s\n",
- defPackage ? String8(*defPackage).string() : "NULL");
- printf("Expanding resource: ref=%s\n", String8(ref).string());
+ defPackage ? String8(*defPackage).c_str() : "NULL");
+ printf("Expanding resource: ref=%s\n", String8(ref).c_str());
printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
- String8(package).string(), String8(type).string(),
- String8(name).string());
+ String8(package).c_str(), String8(type).c_str(),
+ String8(name).c_str());
}
return 0;
}
uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic);
if (kIsDebug) {
printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
- String8(package).string(), String8(type).string(),
- String8(name).string(), res);
+ String8(package).c_str(), String8(type).c_str(),
+ String8(name).c_str(), res);
}
if (res == 0) {
if (outErrorMsg)
@@ -2284,7 +2284,7 @@ uint32_t ResourceTable::getResId(const String16& ref,
bool ResourceTable::isValidResourceName(const String16& s)
{
- const char16_t* p = s.string();
+ const char16_t* p = s.c_str();
bool first = true;
while (*p) {
if ((*p >= 'a' && *p <= 'z')
@@ -2315,7 +2315,7 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
if (style == NULL || style->size() == 0) {
// Text is not styled so it can be any type... let's figure it out.
res = mAssets->getIncludedResources()
- .stringToValue(outValue, &finalStr, str.string(), str.size(), preserveSpaces,
+ .stringToValue(outValue, &finalStr, str.c_str(), str.size(), preserveSpaces,
coerceType, attrID, NULL, &mAssetsPackage, this,
accessorCookie, attrType);
} else {
@@ -2344,7 +2344,7 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
if (kIsDebug) {
printf("Adding to pool string style #%zu config %s: %s\n",
style != NULL ? style->size() : 0U,
- configStr.string(), String8(finalStr).string());
+ configStr.c_str(), String8(finalStr).c_str());
}
if (style != NULL && style->size() > 0) {
outValue->data = pool->add(finalStr, *style, configTypeName, config);
@@ -2368,8 +2368,8 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
uint32_t ResourceTable::getCustomResource(
const String16& package, const String16& type, const String16& name) const
{
- //printf("getCustomResource: %s %s %s\n", String8(package).string(),
- // String8(type).string(), String8(name).string());
+ //printf("getCustomResource: %s %s %s\n", String8(package).c_str(),
+ // String8(type).c_str(), String8(name).c_str());
sp<Package> p = mPackages.valueFor(package);
if (p == NULL) return 0;
sp<Type> t = p->getTypes().valueFor(type);
@@ -2400,7 +2400,7 @@ uint32_t ResourceTable::getCustomResourceWithCreation(
if (mAssetsPackage != package) {
mCurrentXmlPos.error("creating resource for external package %s: %s/%s.",
- String8(package).string(), String8(type).string(), String8(name).string());
+ String8(package).c_str(), String8(type).c_str(), String8(name).c_str());
if (package == String16("android")) {
mCurrentXmlPos.printf("did you mean to use @+id instead of @+android:id?");
}
@@ -2427,7 +2427,7 @@ bool ResourceTable::getAttributeType(uint32_t attrID, uint32_t* outType)
Res_value value;
if (getItemValue(attrID, ResTable_map::ATTR_TYPE, &value)) {
//printf("getAttributeType #%08x (%s): #%08x\n", attrID,
- // String8(getEntry(attrID)->getName()).string(), value.data);
+ // String8(getEntry(attrID)->getName()).c_str(), value.data);
*outType = value.data;
return true;
}
@@ -2481,7 +2481,7 @@ void ResourceTable::reportError(void* accessorCookie, const char* fmt, ...)
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
ac->sourcePos.error("Error: %s (at '%s' with value '%s').\n",
- buf, ac->attr.string(), ac->value.string());
+ buf, ac->attr.c_str(), ac->value.c_str());
}
}
@@ -2493,7 +2493,7 @@ bool ResourceTable::getAttributeKeys(
const size_t N = e->getBag().size();
for (size_t i=0; i<N; i++) {
const String16& key = e->getBag().keyAt(i);
- if (key.size() > 0 && key.string()[0] != '^') {
+ if (key.size() > 0 && key.c_str()[0] != '^') {
outKeys->add(key);
}
}
@@ -2506,14 +2506,14 @@ bool ResourceTable::getAttributeEnum(
uint32_t attrID, const char16_t* name, size_t nameLen,
Res_value* outValue)
{
- //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).string());
+ //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).c_str());
String16 nameStr(name, nameLen);
sp<const Entry> e = getEntry(attrID);
if (e != NULL) {
const size_t N = e->getBag().size();
for (size_t i=0; i<N; i++) {
- //printf("Comparing %s to %s\n", String8(name, nameLen).string(),
- // String8(e->getBag().keyAt(i)).string());
+ //printf("Comparing %s to %s\n", String8(name, nameLen).c_str(),
+ // String8(e->getBag().keyAt(i)).c_str());
if (e->getBag().keyAt(i) == nameStr) {
return getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, outValue);
}
@@ -2529,7 +2529,7 @@ bool ResourceTable::getAttributeFlags(
outValue->dataType = Res_value::TYPE_INT_HEX;
outValue->data = 0;
- //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).string());
+ //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).c_str());
String16 nameStr(name, nameLen);
sp<const Entry> e = getEntry(attrID);
if (e != NULL) {
@@ -2546,8 +2546,8 @@ bool ResourceTable::getAttributeFlags(
String16 nameStr(start, pos-start);
size_t i;
for (i=0; i<N; i++) {
- //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).string(),
- // String8(e->getBag().keyAt(i)).string());
+ //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).c_str(),
+ // String8(e->getBag().keyAt(i)).c_str());
if (e->getBag().keyAt(i) == nameStr) {
Res_value val;
bool got = getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, &val);
@@ -2753,7 +2753,7 @@ status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols,
if (mHasDefaultLocalization.find(c->getName())
== mHasDefaultLocalization.end()) {
// printf("Skip symbol [%08x] %s\n", rid,
- // String8(c->getName()).string());
+ // String8(c->getName()).c_str());
continue;
}
}
@@ -2763,7 +2763,7 @@ status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols,
String16 comment(c->getComment());
typeSymbols->appendComment(String8(c->getName()), comment, c->getPos());
//printf("Type symbol [%08x] %s comment: %s\n", rid,
- // String8(c->getName()).string(), String8(comment).string());
+ // String8(c->getName()).c_str(), String8(comment).c_str());
comment = c->getTypeComment();
typeSymbols->appendTypeComment(String8(c->getName()), comment);
}
@@ -2809,10 +2809,10 @@ ResourceTable::validateLocalizations(void)
// Look for strings with no default localization
if (configSrcMap.count(defaultLocale) == 0) {
SourcePos().warning("string '%s' has no default translation.",
- String8(nameIter.first).string());
+ String8(nameIter.first).c_str());
if (mBundle->getVerbose()) {
for (const auto& locale : configSrcMap) {
- locale.second.printf("locale %s found", locale.first.string());
+ locale.second.printf("locale %s found", locale.first.c_str());
}
}
// !!! TODO: throw an error here in some circumstances
@@ -2820,7 +2820,7 @@ ResourceTable::validateLocalizations(void)
// Check that all requested localizations are present for this string
if (mBundle->getConfigurations().size() > 0 && mBundle->getRequireLocalization()) {
- const char* allConfigs = mBundle->getConfigurations().string();
+ const char* allConfigs = mBundle->getConfigurations().c_str();
const char* start = allConfigs;
const char* comma;
@@ -2847,7 +2847,7 @@ ResourceTable::validateLocalizations(void)
// requiring a specific regional localization [e.g. de_DE] but there is an
// available string in the generic language localization [e.g. de];
// consider that string to have fulfilled the localization requirement.
- String8 region(config.string(), 2);
+ String8 region(config.c_str(), 2);
if (configSrcMap.find(region) == configSrcMap.end() &&
configSrcMap.count(defaultLocale) == 0) {
missingConfigs.insert(config);
@@ -2859,12 +2859,12 @@ ResourceTable::validateLocalizations(void)
if (!missingConfigs.empty()) {
String8 configStr;
for (const auto& iter : missingConfigs) {
- configStr.appendFormat(" %s", iter.string());
+ configStr.appendFormat(" %s", iter.c_str());
}
SourcePos().warning("string '%s' is missing %u required localizations:%s",
- String8(nameIter.first).string(),
+ String8(nameIter.first).c_str(),
(unsigned int)missingConfigs.size(),
- configStr.string());
+ configStr.c_str());
}
}
}
@@ -3021,7 +3021,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
header->header.type = htods(RES_TABLE_PACKAGE_TYPE);
header->header.headerSize = htods(sizeof(*header));
header->id = htodl(static_cast<uint32_t>(p->getAssignedId()));
- strcpy16_htod(header->name, p->getName().string());
+ strcpy16_htod(header->name, p->getName().c_str());
// Write the string blocks.
const size_t typeStringsStart = data->getSize();
@@ -3061,7 +3061,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
sp<Type> t = p->getTypes().valueFor(typeName);
LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"),
"Type name %s not found",
- String8(typeName).string());
+ String8(typeName).c_str());
if (t == NULL) {
continue;
}
@@ -3260,7 +3260,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
if (c != NULL) {
fprintf(stderr, "%s: no entries written for %s/%s (0x%08zx)\n", log_prefix,
- String8(typeName).string(), String8(c->getName()).string(),
+ String8(typeName).c_str(), String8(c->getName()).c_str(),
Res_MAKEID(p->getAssignedId() - 1, ti, i));
}
missing_entry = true;
@@ -3359,7 +3359,7 @@ status_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vect
sp<Package> libPackage = libs[i];
if (kIsDebug) {
fprintf(stderr, " Entry %s -> 0x%02x\n",
- String8(libPackage->getName()).string(),
+ String8(libPackage->getName()).c_str(),
(uint8_t)libPackage->getAssignedId());
}
@@ -3367,7 +3367,7 @@ status_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vect
entryStart, sizeof(ResTable_lib_entry));
memset(entry, 0, sizeof(*entry));
entry->packageId = htodl(libPackage->getAssignedId());
- strcpy16_htod(entry->packageName, libPackage->getName().string());
+ strcpy16_htod(entry->packageName, libPackage->getName().c_str());
}
}
return NO_ERROR;
@@ -3435,13 +3435,13 @@ void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp, bo
const SourcePos& pos = c->getEntries().valueAt(k)->getPos();
if (pos.file != "") {
fprintf(fp," <!-- Declared at %s:%d -->\n",
- pos.file.string(), pos.line);
+ pos.file.c_str(), pos.line);
}
}
}
fprintf(fp, " <public type=\"%s\" name=\"%s\" id=\"0x%08x\" />\n",
- String8(t->getName()).string(),
- String8(c->getName()).string(),
+ String8(t->getName()).c_str(),
+ String8(c->getName()).c_str(),
getResId(pkg, t, c->getEntryIndex()));
}
}
@@ -3501,8 +3501,8 @@ status_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos)
}
sourcePos.error("Resource entry %s is already defined as a single item.\n"
"%s:%d: Originally defined here.\n",
- String8(mName).string(),
- mItem.sourcePos.file.string(), mItem.sourcePos.line);
+ String8(mName).c_str(),
+ mItem.sourcePos.file.c_str(), mItem.sourcePos.line);
return UNKNOWN_ERROR;
}
@@ -3517,21 +3517,21 @@ status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos,
if (mType == TYPE_BAG) {
if (mBag.size() == 0) {
sourcePos.error("Resource entry %s is already defined as a bag.",
- String8(mName).string());
+ String8(mName).c_str());
} else {
const Item& item(mBag.valueAt(0));
sourcePos.error("Resource entry %s is already defined as a bag.\n"
"%s:%d: Originally defined here.\n",
- String8(mName).string(),
- item.sourcePos.file.string(), item.sourcePos.line);
+ String8(mName).c_str(),
+ item.sourcePos.file.c_str(), item.sourcePos.line);
}
return UNKNOWN_ERROR;
}
if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) {
sourcePos.error("Resource entry %s is already defined.\n"
"%s:%d: Originally defined here.\n",
- String8(mName).string(),
- mItem.sourcePos.file.string(), mItem.sourcePos.line);
+ String8(mName).c_str(),
+ mItem.sourcePos.file.c_str(), mItem.sourcePos.line);
return UNKNOWN_ERROR;
}
@@ -3562,12 +3562,12 @@ status_t ResourceTable::Entry::addToBag(const SourcePos& sourcePos,
const Item& item(mBag.valueAt(origKey));
sourcePos.error("Resource entry %s already has bag item %s.\n"
"%s:%d: Originally defined here.\n",
- String8(mName).string(), String8(key).string(),
- item.sourcePos.file.string(), item.sourcePos.line);
+ String8(mName).c_str(), String8(key).c_str(),
+ item.sourcePos.file.c_str(), item.sourcePos.line);
return UNKNOWN_ERROR;
}
//printf("Replacing %s with %s\n",
- // String8(mBag.valueFor(key).value).string(), String8(value).string());
+ // String8(mBag.valueFor(key).value).c_str(), String8(value).c_str());
mBag.replaceValueFor(key, item);
}
@@ -3611,8 +3611,8 @@ status_t ResourceTable::Entry::generateAttributes(ResourceTable* table,
String16 value("false");
if (kIsDebug) {
fprintf(stderr, "Generating %s:id/%s\n",
- String8(package).string(),
- String8(key).string());
+ String8(package).c_str(),
+ String8(key).c_str());
}
status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package,
id16, key, value);
@@ -3624,10 +3624,10 @@ status_t ResourceTable::Entry::generateAttributes(ResourceTable* table,
#if 1
// fprintf(stderr, "ERROR: Bag attribute '%s' has not been defined.\n",
-// String8(key).string());
+// String8(key).c_str());
// const Item& item(mBag.valueAt(i));
// fprintf(stderr, "Referenced from file %s line %d\n",
-// item.sourcePos.file.string(), item.sourcePos.line);
+// item.sourcePos.file.c_str(), item.sourcePos.line);
// return UNKNOWN_ERROR;
#else
char numberStr[16];
@@ -3660,7 +3660,7 @@ status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table,
mParentId = table->getResId(mParent, &style16, NULL, &errorMsg);
if (mParentId == 0) {
mPos.error("Error retrieving parent for item: %s '%s'.\n",
- errorMsg, String8(mParent).string());
+ errorMsg, String8(mParent).c_str());
hasErrors = true;
}
}
@@ -3670,11 +3670,11 @@ status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table,
Item& it = mBag.editValueAt(i);
it.bagKeyId = table->getResId(key,
it.isId ? &id16 : &attr16, NULL, &errorMsg);
- //printf("Bag key of %s: #%08x\n", String8(key).string(), it.bagKeyId);
+ //printf("Bag key of %s: #%08x\n", String8(key).c_str(), it.bagKeyId);
if (it.bagKeyId == 0) {
it.sourcePos.error("Error: %s: %s '%s'.\n", errorMsg,
- String8(it.isId ? id16 : attr16).string(),
- String8(key).string());
+ String8(it.isId ? id16 : attr16).c_str(),
+ String8(key).c_str());
hasErrors = true;
}
}
@@ -3709,7 +3709,7 @@ status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable
}
} else {
mPos.error("Error: entry %s is not a single item or a bag.\n",
- String8(mName).string());
+ String8(mName).c_str());
return UNKNOWN_ERROR;
}
return NO_ERROR;
@@ -3732,7 +3732,7 @@ status_t ResourceTable::Entry::remapStringValue(StringPool* strings)
}
} else {
mPos.error("Error: entry %s is not a single item or a bag.\n",
- String8(mName).string());
+ String8(mName).c_str());
return UNKNOWN_ERROR;
}
return NO_ERROR;
@@ -3768,7 +3768,7 @@ ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp<AaptFile>&
par.data = htodl(it.parsedValue.data);
#if 0
printf("Writing item (%s): type=%d, data=0x%x, res0=0x%x\n",
- String8(mName).string(), it.parsedValue.dataType,
+ String8(mName).c_str(), it.parsedValue.dataType,
it.parsedValue.data, par.res0);
#endif
err = data->writeData(&par, it.parsedValue.size);
@@ -3852,7 +3852,7 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
int32_t entryIdx = Res_GETENTRY(ident);
if (entryIdx < 0) {
sourcePos.error("Public resource %s/%s has an invalid 0 identifier (0x%08x).\n",
- String8(mName).string(), String8(name).string(), ident);
+ String8(mName).c_str(), String8(name).c_str(), ident);
return UNKNOWN_ERROR;
}
#endif
@@ -3863,7 +3863,7 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
if (mPublicIndex > 0 && mPublicIndex != typeIdx) {
sourcePos.error("Public resource %s/%s has conflicting type codes for its"
" public identifiers (0x%x vs 0x%x).\n",
- String8(mName).string(), String8(name).string(),
+ String8(mName).c_str(), String8(name).c_str(),
mPublicIndex, typeIdx);
return UNKNOWN_ERROR;
}
@@ -3882,8 +3882,8 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
sourcePos.error("Public resource %s/%s has conflicting public identifiers"
" (0x%08x vs 0x%08x).\n"
"%s:%d: Originally defined here.\n",
- String8(mName).string(), String8(name).string(), p.ident, ident,
- p.sourcePos.file.string(), p.sourcePos.line);
+ String8(mName).c_str(), String8(name).c_str(), p.ident, ident,
+ p.sourcePos.file.c_str(), p.sourcePos.line);
return UNKNOWN_ERROR;
}
}
@@ -3909,7 +3909,7 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
if (overlay && !autoAddOverlay && mCanAddEntries.indexOf(entry) < 0) {
sourcePos.error("Resource at %s appears in overlay but not"
" in the base package; use <add-resource> to add.\n",
- String8(entry).string());
+ String8(entry).c_str());
return NULL;
}
c = new ConfigList(entry, sourcePos);
@@ -3931,7 +3931,7 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
"orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
"sw%ddp w%ddp h%ddp layout:%d\n",
- sourcePos.file.string(), sourcePos.line,
+ sourcePos.file.c_str(), sourcePos.line,
config->mcc, config->mnc,
config->language[0] ? config->language[0] : '-',
config->language[1] ? config->language[1] : '-',
@@ -3951,7 +3951,7 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
config->screenLayout);
} else {
printf("New entry at %s:%d: NULL config\n",
- sourcePos.file.string(), sourcePos.line);
+ sourcePos.file.c_str(), sourcePos.line);
}
}
e = new Entry(entry, sourcePos);
@@ -4032,11 +4032,11 @@ status_t ResourceTable::Type::applyPublicEntryOrder()
const Public& p = mPublic.valueAt(j);
int32_t idx = Res_GETENTRY(p.ident);
//printf("Looking for entry \"%s\"/\"%s\" (0x%08x) in %d...\n",
- // String8(mName).string(), String8(name).string(), p.ident, N);
+ // String8(mName).c_str(), String8(name).c_str(), p.ident, N);
bool found = false;
for (i=0; i<N; i++) {
sp<ConfigList> e = origOrder.itemAt(i);
- //printf("#%d: \"%s\"\n", i, String8(e->getName()).string());
+ //printf("#%d: \"%s\"\n", i, String8(e->getName()).c_str());
if (e->getName() == name) {
if (idx >= (int32_t)mOrderedConfigs.size()) {
mOrderedConfigs.resize(idx + 1);
@@ -4056,10 +4056,10 @@ status_t ResourceTable::Type::applyPublicEntryOrder()
p.sourcePos.error("Multiple entry names declared for public entry"
" identifier 0x%x in type %s (%s vs %s).\n"
"%s:%d: Originally defined here.",
- idx+1, String8(mName).string(),
- String8(oe->getName()).string(),
- String8(name).string(),
- oe->getPublicSourcePos().file.string(),
+ idx+1, String8(mName).c_str(),
+ String8(oe->getName()).c_str(),
+ String8(name).c_str(),
+ oe->getPublicSourcePos().file.c_str(),
oe->getPublicSourcePos().line);
hasError = true;
}
@@ -4068,7 +4068,7 @@ status_t ResourceTable::Type::applyPublicEntryOrder()
if (!found) {
p.sourcePos.error("Public symbol %s/%s declared here is not defined.",
- String8(mName).string(), String8(name).string());
+ String8(mName).c_str(), String8(name).c_str());
hasError = true;
}
}
@@ -4189,9 +4189,9 @@ status_t ResourceTable::Package::applyPublicTypeOrder()
t->getFirstPublicSourcePos().error("Multiple type names declared for public type"
" identifier 0x%x (%s vs %s).\n"
"%s:%d: Originally defined here.",
- idx, String8(ot->getName()).string(),
- String8(t->getName()).string(),
- ot->getFirstPublicSourcePos().file.string(),
+ idx, String8(ot->getName()).c_str(),
+ String8(t->getName()).c_str(),
+ ot->getFirstPublicSourcePos().file.c_str(),
ot->getFirstPublicSourcePos().line);
return UNKNOWN_ERROR;
}
@@ -4399,8 +4399,8 @@ const ResourceTable::Item* ResourceTable::getItem(uint32_t resID, uint32_t attrI
const Item& it = e->getBag().valueAt(i);
if (it.bagKeyId == 0) {
fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n",
- String8(e->getName()).string(),
- String8(e->getBag().keyAt(i)).string());
+ String8(e->getName()).c_str(),
+ String8(e->getBag().keyAt(i)).c_str());
}
if (it.bagKeyId == attrID) {
return &it;
@@ -4427,8 +4427,8 @@ bool ResourceTable::getItemValue(
}
}
fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n",
- String8(e->getName()).string(),
- String8(e->getBag().keyAt(i)).string());
+ String8(e->getName()).c_str(),
+ String8(e->getBag().keyAt(i)).c_str());
return false;
}
item->evaluating = true;
@@ -4436,7 +4436,7 @@ bool ResourceTable::getItemValue(
if (kIsDebug) {
if (res) {
printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n",
- resID, attrID, String8(getEntry(resID)->getName()).string(),
+ resID, attrID, String8(getEntry(resID)->getName()).c_str(),
outValue->dataType, outValue->data);
} else {
printf("getItemValue of #%08x[#%08x]: failed\n",
@@ -4713,10 +4713,10 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
entriesToAdd[i].value->getPos()
.printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
entriesToAdd[i].key.sdkVersion,
- String8(p->getName()).string(),
- String8(t->getName()).string(),
- String8(entriesToAdd[i].value->getName()).string(),
- entriesToAdd[i].key.toString().string());
+ String8(p->getName()).c_str(),
+ String8(t->getName()).c_str(),
+ String8(entriesToAdd[i].value->getName()).c_str(),
+ entriesToAdd[i].key.toString().c_str());
}
sp<Entry> newEntry = t->getEntry(c->getName(),
@@ -4801,8 +4801,8 @@ bool ResourceTable::versionForCompat(const Bundle* bundle, const String16& resou
sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
AaptGroupEntry(newConfig), target->getResourceType());
String8 resPath = String8::format("res/%s/%s.xml",
- newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
- String8(resourceName).string());
+ newFile->getGroupEntry().toDirName(target->getResourceType()).c_str(),
+ String8(resourceName).c_str());
resPath.convertToResPath();
// Add a resource table entry.
@@ -4893,10 +4893,10 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
if (bundle->getVerbose()) {
SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
"removing attribute %s%s%s from <%s>",
- String8(attr.ns).string(),
+ String8(attr.ns).c_str(),
(attr.ns.size() == 0 ? "" : ":"),
- String8(attr.name).string(),
- String8(node->getElementName()).string());
+ String8(attr.name).c_str(),
+ String8(node->getElementName()).c_str());
}
node->removeAttribute(i);
i--;
@@ -4925,8 +4925,8 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
AaptGroupEntry(newConfig), target->getResourceType());
String8 resPath = String8::format("res/%s/%s.xml",
- newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
- String8(resourceName).string());
+ newFile->getGroupEntry().toDirName(target->getResourceType()).c_str(),
+ String8(resourceName).c_str());
resPath.convertToResPath();
// Add a resource table entry.
@@ -4934,10 +4934,10 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
SourcePos(target->getSourceFile(), -1).printf(
"using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
newConfig.sdkVersion,
- mAssets->getPackage().string(),
- newFile->getResourceType().string(),
- String8(resourceName).string(),
- newConfig.toString().string());
+ mAssets->getPackage().c_str(),
+ newFile->getResourceType().c_str(),
+ String8(resourceName).c_str(),
+ newConfig.toString().c_str());
}
addEntry(SourcePos(),
@@ -5114,8 +5114,8 @@ status_t ResourceTable::processBundleFormatImpl(const Bundle* bundle,
sp<XMLNode> nestedRoot = findOnlyChildElement(child);
if (nestedRoot == NULL) {
source.error("<%s:%s> must have exactly one child element",
- String8(child->getElementNamespace()).string(),
- String8(child->getElementName()).string());
+ String8(child->getElementNamespace()).c_str(),
+ String8(child->getElementName()).c_str());
return UNKNOWN_ERROR;
}
@@ -5130,7 +5130,7 @@ status_t ResourceTable::processBundleFormatImpl(const Bundle* bundle,
// Parse the attribute name.
const char* errorMsg = NULL;
String16 attrPackage, attrType, attrName;
- bool result = ResTable::expandResourceRef(attr->string.string(),
+ bool result = ResTable::expandResourceRef(attr->string.c_str(),
attr->string.size(),
&attrPackage, &attrType, &attrName,
&kAttr16, &kAssetPackage16,
@@ -5156,11 +5156,11 @@ status_t ResourceTable::processBundleFormatImpl(const Bundle* bundle,
// This child element will be extracted into its own resource file.
// Generate a name and path for it from its parent.
nestedResourceName = String8::format("%s_%d",
- String8(resourceName).string(), suffix++);
+ String8(resourceName).c_str(), suffix++);
nestedResourcePath = String8::format("res/%s/%s.xml",
target->getGroupEntry().toDirName(target->getResourceType())
- .string(),
- nestedResourceName.string());
+ .c_str(),
+ nestedResourceName.c_str());
// Lookup or create the entry for this name.
sp<Entry> entry = getEntry(kAssetPackage16,
@@ -5187,20 +5187,20 @@ status_t ResourceTable::processBundleFormatImpl(const Bundle* bundle,
if (bundle->getVerbose()) {
source.printf("generating nested resource %s:%s/%s",
- mAssets->getPackage().string(), target->getResourceType().string(),
- nestedResourceName.string());
+ mAssets->getPackage().c_str(), target->getResourceType().c_str(),
+ nestedResourceName.c_str());
}
// Build the attribute reference and assign it to the parent.
String16 nestedResourceRef = String16(String8::format("@%s:%s/%s",
- mAssets->getPackage().string(), target->getResourceType().string(),
- nestedResourceName.string()));
+ mAssets->getPackage().c_str(), target->getResourceType().c_str(),
+ nestedResourceName.c_str()));
String16 attrNs = buildNamespace(attrPackage);
if (parent->getAttribute(attrNs, attrName) != NULL) {
SourcePos(parent->getFilename(), parent->getStartLineNumber())
.error("parent of nested resource already defines attribute '%s:%s'",
- String8(attrPackage).string(), String8(attrName).string());
+ String8(attrPackage).c_str(), String8(attrName).c_str());
return UNKNOWN_ERROR;
}
diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp
index 38643201c22d..e13028684414 100644
--- a/tools/aapt/SourcePos.cpp
+++ b/tools/aapt/SourcePos.cpp
@@ -80,12 +80,12 @@ ErrorPos::print(FILE* to) const
if (!this->file.isEmpty()) {
if (this->line >= 0) {
- fprintf(to, "%s:%d: %s%s\n", this->file.string(), this->line, type, this->error.string());
+ fprintf(to, "%s:%d: %s%s\n", this->file.c_str(), this->line, type, this->error.c_str());
} else {
- fprintf(to, "%s: %s%s\n", this->file.string(), type, this->error.string());
+ fprintf(to, "%s: %s%s\n", this->file.c_str(), type, this->error.c_str());
}
} else {
- fprintf(to, "%s%s\n", type, this->error.string());
+ fprintf(to, "%s%s\n", type, this->error.c_str());
}
}
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 6cacd32eb91d..8d0268393433 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -67,7 +67,7 @@ void printStringPool(const ResStringPool* pool)
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
auto str = pool->string8ObjectAt(s);
- printf("String #" ZD ": %s\n", (ZD_TYPE) s, (str.has_value() ? str->string() : ""));
+ printf("String #" ZD ": %s\n", (ZD_TYPE) s, (str.has_value() ? str->c_str() : ""));
}
}
@@ -139,7 +139,7 @@ ssize_t StringPool::add(const String16& value,
if (eidx < 0) {
eidx = mEntries.add(entry(value));
if (eidx < 0) {
- fprintf(stderr, "Failure adding string %s\n", String8(value).string());
+ fprintf(stderr, "Failure adding string %s\n", String8(value).c_str());
return eidx;
}
}
@@ -148,7 +148,7 @@ ssize_t StringPool::add(const String16& value,
entry& ent = mEntries.editItemAt(eidx);
if (kIsDebug) {
printf("*** adding config type name %s, was %s\n",
- configTypeName->string(), ent.configTypeName.string());
+ configTypeName->c_str(), ent.configTypeName.c_str());
}
if (ent.configTypeName.size() <= 0) {
ent.configTypeName = *configTypeName;
@@ -166,7 +166,7 @@ ssize_t StringPool::add(const String16& value,
if (cmp >= 0) {
if (cmp > 0) {
if (kIsDebug) {
- printf("*** inserting config: %s\n", config->toString().string());
+ printf("*** inserting config: %s\n", config->toString().c_str());
}
ent.configs.insertAt(*config, addPos);
}
@@ -175,7 +175,7 @@ ssize_t StringPool::add(const String16& value,
}
if (addPos >= ent.configs.size()) {
if (kIsDebug) {
- printf("*** adding config: %s\n", config->toString().string());
+ printf("*** adding config: %s\n", config->toString().c_str());
}
ent.configs.add(*config);
}
@@ -195,7 +195,7 @@ ssize_t StringPool::add(const String16& value,
if (kIsDebug) {
printf("Adding string %s to pool: pos=%zd eidx=%zd vidx=%zd\n",
- String8(value).string(), pos, eidx, vidx);
+ String8(value).c_str(), pos, eidx, vidx);
}
return pos;
@@ -286,13 +286,13 @@ void StringPool::sortByConfig()
for (size_t i=0; i<N; i++) {
printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
- mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
+ mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().c_str());
entries.add(mEntries[mEntryArray[i]]);
}
for (size_t i=0; i<entries.size(); i++) {
printf("Sorted config #%d: %s\n", i,
- entries[i].makeConfigsString().string());
+ entries[i].makeConfigsString().c_str());
}
#endif
@@ -363,8 +363,8 @@ void StringPool::sortByConfig()
printf("FINAL SORTED STRING CONFIGS:\n");
for (size_t i=0; i<mEntries.size(); i++) {
const entry& ent = mEntries[i];
- printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
- String8(ent.value).string());
+ printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().c_str(),
+ String8(ent.value).c_str());
}
#endif
}
@@ -415,7 +415,7 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
ssize_t idx = add(span.name, true);
if (idx < 0) {
fprintf(stderr, "Error adding span for style tag '%s'\n",
- String8(span.name).string());
+ String8(span.name).c_str());
return idx;
}
span.span.name.index = (uint32_t)idx;
@@ -571,7 +571,7 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
if (kIsDebug) {
printf("Writing entry #%zu: \"%s\" ent=%zu off=%zu\n",
i,
- String8(ent.value).string(),
+ String8(ent.value).c_str(),
mEntryArray[i],
ent.offset);
}
@@ -591,8 +591,8 @@ ssize_t StringPool::offsetForString(const String16& val) const
const Vector<size_t>* indices = offsetsForString(val);
ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
if (kIsDebug) {
- printf("Offset for string %s: %zd (%s)\n", String8(val).string(), res,
- res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8());
+ printf("Offset for string %s: %zd (%s)\n", String8(val).c_str(), res,
+ res >= 0 ? String8(mEntries[mEntryArray[res]].value).c_str() : String8());
}
return res;
}
diff --git a/tools/aapt/Symbol.h b/tools/aapt/Symbol.h
index e1575410e38b..de1d60cbae42 100644
--- a/tools/aapt/Symbol.h
+++ b/tools/aapt/Symbol.h
@@ -68,9 +68,9 @@ Symbol::Symbol(const android::String16& p, const android::String16& t, const and
android::String8 Symbol::toString() const {
return android::String8::format("%s:%s/%s (0x%08x)",
- android::String8(package).string(),
- android::String8(type).string(),
- android::String8(name).string(),
+ android::String8(package).c_str(),
+ android::String8(type).c_str(),
+ android::String8(name).c_str(),
(int) id);
}
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 69392d66e21f..e270a7333295 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -66,14 +66,14 @@ static const String16 RESOURCES_TOOLS_NAMESPACE("http://schemas.android.com/tool
String16 getNamespaceResourcePackage(const String16& appPackage, const String16& namespaceUri, bool* outIsPublic)
{
- //printf("%s starts with %s?\n", String8(namespaceUri).string(),
- // String8(RESOURCES_PREFIX).string());
+ //printf("%s starts with %s?\n", String8(namespaceUri).c_str(),
+ // String8(RESOURCES_PREFIX).c_str());
size_t prefixSize;
bool isPublic = true;
if(namespaceUri.startsWith(RESOURCES_PREFIX_AUTO_PACKAGE)) {
if (kIsDebug) {
- printf("Using default application package: %s -> %s\n", String8(namespaceUri).string(),
- String8(appPackage).string());
+ printf("Using default application package: %s -> %s\n", String8(namespaceUri).c_str(),
+ String8(appPackage).c_str());
}
isPublic = true;
return appPackage;
@@ -88,7 +88,7 @@ String16 getNamespaceResourcePackage(const String16& appPackage, const String16&
}
//printf("YES!\n");
- //printf("namespace: %s\n", String8(String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize)).string());
+ //printf("namespace: %s\n", String8(String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize)).c_str());
if (outIsPublic) *outIsPublic = isPublic;
return String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize);
}
@@ -97,7 +97,7 @@ status_t hasSubstitutionErrors(const char* fileName,
ResXMLTree* inXml,
const String16& str16)
{
- const char16_t* str = str16.string();
+ const char16_t* str = str16.c_str();
const char16_t* p = str;
const char16_t* end = str + str16.size();
@@ -223,7 +223,7 @@ status_t parseStyledString(Bundle* /* bundle */,
String16 text(inXml->getText(&len));
if (firstTime && text.size() > 0) {
firstTime = false;
- if (text.string()[0] == '@') {
+ if (text.c_str()[0] == '@') {
// If this is a resource reference, don't do the pseudoloc.
pseudolocalize = NO_PSEUDOLOCALIZATION;
pseudo.setMethod(pseudolocalize);
@@ -263,7 +263,7 @@ status_t parseStyledString(Bundle* /* bundle */,
{
SourcePos(String8(fileName), inXml->getLineNumber()).error(
"Found unsupported XLIFF tag <%s>\n",
- element8.string());
+ element8.c_str());
return UNKNOWN_ERROR;
}
moveon:
@@ -272,14 +272,14 @@ moveon:
if (outSpans == NULL) {
SourcePos(String8(fileName), inXml->getLineNumber()).error(
- "Found style tag <%s> where styles are not allowed\n", element8.string());
+ "Found style tag <%s> where styles are not allowed\n", element8.c_str());
return UNKNOWN_ERROR;
}
- if (!ResTable::collectString(outString, curString.string(),
+ if (!ResTable::collectString(outString, curString.c_str(),
curString.size(), false, &errorMsg, true)) {
SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n",
- errorMsg, String8(curString).string());
+ errorMsg, String8(curString).c_str());
return UNKNOWN_ERROR;
}
rawString.append(curString);
@@ -295,7 +295,7 @@ moveon:
str = inXml->getAttributeStringValue(ai, &len);
span.name.append(str, len);
}
- //printf("Span: %s\n", String8(span.name).string());
+ //printf("Span: %s\n", String8(span.name).c_str());
span.span.firstChar = span.span.lastChar = outString->size();
spanStack.push(span);
@@ -311,21 +311,21 @@ moveon:
xliffDepth--;
continue;
}
- if (!ResTable::collectString(outString, curString.string(),
+ if (!ResTable::collectString(outString, curString.c_str(),
curString.size(), false, &errorMsg, true)) {
SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n",
- errorMsg, String8(curString).string());
+ errorMsg, String8(curString).c_str());
return UNKNOWN_ERROR;
}
rawString.append(curString);
curString = String16();
if (spanStack.size() == 0) {
- if (strcmp16(inXml->getElementName(&len), endTag.string()) != 0) {
+ if (strcmp16(inXml->getElementName(&len), endTag.c_str()) != 0) {
SourcePos(String8(fileName), inXml->getLineNumber()).error(
"Found tag %s where <%s> close is expected\n",
- String8(inXml->getElementName(&len)).string(),
- String8(endTag).string());
+ String8(inXml->getElementName(&len)).c_str(),
+ String8(endTag).c_str());
return UNKNOWN_ERROR;
}
break;
@@ -334,15 +334,15 @@ moveon:
String16 spanTag;
ssize_t semi = span.name.findFirst(';');
if (semi >= 0) {
- spanTag.setTo(span.name.string(), semi);
+ spanTag.setTo(span.name.c_str(), semi);
} else {
spanTag.setTo(span.name);
}
- if (strcmp16(inXml->getElementName(&len), spanTag.string()) != 0) {
+ if (strcmp16(inXml->getElementName(&len), spanTag.c_str()) != 0) {
SourcePos(String8(fileName), inXml->getLineNumber()).error(
"Found close tag %s where close tag %s is expected\n",
- String8(inXml->getElementName(&len)).string(),
- String8(spanTag).string());
+ String8(inXml->getElementName(&len)).c_str(),
+ String8(spanTag).c_str());
return UNKNOWN_ERROR;
}
bool empty = true;
@@ -363,7 +363,7 @@ moveon:
if (0 && empty) {
fprintf(stderr, "%s:%d: warning: empty '%s' span found in text '%s'\n",
fileName, inXml->getLineNumber(),
- String8(spanTag).string(), String8(*outString).string());
+ String8(spanTag).c_str(), String8(*outString).c_str());
}
} else if (code == ResXMLTree::START_NAMESPACE) {
@@ -380,11 +380,11 @@ moveon:
if (outSpans != NULL && outSpans->size() > 0) {
if (curString.size() > 0) {
- if (!ResTable::collectString(outString, curString.string(),
+ if (!ResTable::collectString(outString, curString.c_str(),
curString.size(), false, &errorMsg, true)) {
SourcePos(String8(fileName), inXml->getLineNumber()).error(
"%s (in %s)\n",
- errorMsg, String8(curString).string());
+ errorMsg, String8(curString).c_str());
return UNKNOWN_ERROR;
}
}
@@ -450,10 +450,10 @@ void printXMLBlock(ResXMLTree* block)
String8 elemNs = build_namespace(namespaces, ns16);
const char16_t* com16 = block->getComment(&len);
if (com16) {
- printf("%s <!-- %s -->\n", prefix.string(), String8(com16).string());
+ printf("%s <!-- %s -->\n", prefix.c_str(), String8(com16).c_str());
}
- printf("%sE: %s%s (line=%d)\n", prefix.string(), elemNs.string(),
- String8(block->getElementName(&len)).string(),
+ printf("%sE: %s%s (line=%d)\n", prefix.c_str(), elemNs.c_str(),
+ String8(block->getElementName(&len)).c_str(),
block->getLineNumber());
int N = block->getAttributeCount();
depth++;
@@ -463,11 +463,11 @@ void printXMLBlock(ResXMLTree* block)
ns16 = block->getAttributeNamespace(i, &len);
String8 ns = build_namespace(namespaces, ns16);
String8 name(block->getAttributeName(i, &len));
- printf("%sA: ", prefix.string());
+ printf("%sA: ", prefix.c_str());
if (res) {
- printf("%s%s(0x%08x)", ns.string(), name.string(), res);
+ printf("%s%s(0x%08x)", ns.c_str(), name.c_str(), res);
} else {
- printf("%s%s", ns.string(), name.string());
+ printf("%s%s", ns.c_str(), name.c_str());
}
Res_value value;
block->getAttributeValue(i, &value);
@@ -480,14 +480,14 @@ void printXMLBlock(ResXMLTree* block)
} else if (value.dataType == Res_value::TYPE_STRING) {
printf("=\"%s\"",
ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i,
- &len)).string()).string());
+ &len)).c_str()).c_str());
} else {
printf("=(type 0x%x)0x%x", (int)value.dataType, (int)value.data);
}
const char16_t* val = block->getAttributeStringValue(i, &len);
if (val != NULL) {
- printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).string()).
- string());
+ printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).c_str()).
+ c_str());
}
printf("\n");
}
@@ -509,8 +509,8 @@ void printXMLBlock(ResXMLTree* block)
}
ns.uri = String8(block->getNamespaceUri(&len));
namespaces.push(ns);
- printf("%sN: %s=%s\n", prefix.string(), ns.prefix.string(),
- ns.uri.string());
+ printf("%sN: %s=%s\n", prefix.c_str(), ns.prefix.c_str(),
+ ns.uri.c_str());
depth++;
} else if (code == ResXMLTree::END_NAMESPACE) {
if (--depth < 0) {
@@ -529,19 +529,19 @@ void printXMLBlock(ResXMLTree* block)
if (ns.prefix != pr) {
prefix = make_prefix(depth);
printf("%s*** BAD END NS PREFIX: found=%s, expected=%s\n",
- prefix.string(), pr.string(), ns.prefix.string());
+ prefix.c_str(), pr.c_str(), ns.prefix.c_str());
}
String8 uri = String8(block->getNamespaceUri(&len));
if (ns.uri != uri) {
prefix = make_prefix(depth);
printf("%s *** BAD END NS URI: found=%s, expected=%s\n",
- prefix.string(), uri.string(), ns.uri.string());
+ prefix.c_str(), uri.c_str(), ns.uri.c_str());
}
namespaces.pop();
} else if (code == ResXMLTree::TEXT) {
size_t len;
- printf("%sC: \"%s\"\n", prefix.string(),
- ResTable::normalizeForOutput(String8(block->getText(&len)).string()).string());
+ printf("%sC: \"%s\"\n", prefix.c_str(),
+ ResTable::normalizeForOutput(String8(block->getText(&len)).c_str()).c_str());
}
}
@@ -583,7 +583,7 @@ status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree,
sp<XMLNode> XMLNode::parse(const sp<AaptFile>& file)
{
char buf[16384];
- int fd = open(file->getSourceFile().string(), O_RDONLY | O_BINARY);
+ int fd = open(file->getSourceFile().c_str(), O_RDONLY | O_BINARY);
if (fd < 0) {
SourcePos(file->getSourceFile(), -1).error("Unable to open file for read: %s",
strerror(errno));
@@ -875,9 +875,9 @@ void XMLNode::setAttributeResID(size_t attrIdx, uint32_t resId)
}
if (kIsDebug) {
printf("Elem %s %s=\"%s\": set res id = 0x%08x\n",
- String8(getElementName()).string(),
- String8(mAttributes.itemAt(attrIdx).name).string(),
- String8(mAttributes.itemAt(attrIdx).string).string(),
+ String8(getElementName()).c_str(),
+ String8(mAttributes.itemAt(attrIdx).name).c_str(),
+ String8(mAttributes.itemAt(attrIdx).string).c_str(),
resId);
}
mAttributes.editItemAt(attrIdx).nameResId = resId;
@@ -915,7 +915,7 @@ void XMLNode::setEndLineNumber(int32_t line)
void XMLNode::removeWhitespace(bool stripAll, const char** cDataTags)
{
- //printf("Removing whitespace in %s\n", String8(mElementName).string());
+ //printf("Removing whitespace in %s\n", String8(mElementName).c_str());
size_t N = mChildren.size();
if (cDataTags) {
String8 tag(mElementName);
@@ -931,13 +931,13 @@ void XMLNode::removeWhitespace(bool stripAll, const char** cDataTags)
sp<XMLNode> node = mChildren.itemAt(i);
if (node->getType() == TYPE_CDATA) {
// This is a CDATA node...
- const char16_t* p = node->mChars.string();
+ const char16_t* p = node->mChars.c_str();
while (*p != 0 && *p < 128 && isspace(*p)) {
p++;
}
//printf("Space ends at %d in \"%s\"\n",
- // (int)(p-node->mChars.string()),
- // String8(node->mChars).string());
+ // (int)(p-node->mChars.c_str()),
+ // String8(node->mChars).c_str());
if (*p == 0) {
if (stripAll) {
// Remove this node!
@@ -949,18 +949,18 @@ void XMLNode::removeWhitespace(bool stripAll, const char** cDataTags)
}
} else {
// Compact leading/trailing whitespace.
- const char16_t* e = node->mChars.string()+node->mChars.size()-1;
+ const char16_t* e = node->mChars.c_str()+node->mChars.size()-1;
while (e > p && *e < 128 && isspace(*e)) {
e--;
}
- if (p > node->mChars.string()) {
+ if (p > node->mChars.c_str()) {
p--;
}
- if (e < (node->mChars.string()+node->mChars.size()-1)) {
+ if (e < (node->mChars.c_str()+node->mChars.size()-1)) {
e++;
}
- if (p > node->mChars.string() ||
- e < (node->mChars.string()+node->mChars.size()-1)) {
+ if (p > node->mChars.c_str() ||
+ e < (node->mChars.c_str()+node->mChars.size()-1)) {
String16 tmp(p, e-p+1);
node->mChars = tmp;
}
@@ -986,14 +986,14 @@ status_t XMLNode::parseValues(const sp<AaptAssets>& assets,
table->setCurrentXmlPos(SourcePos(mFilename, getStartLineNumber()));
if (!assets->getIncludedResources()
.stringToValue(&e.value, &e.string,
- e.string.string(), e.string.size(), true, true,
+ e.string.c_str(), e.string.size(), true, true,
e.nameResId, NULL, &defPackage, table, &ac)) {
hasErrors = true;
}
if (kIsDebug) {
printf("Attr %s: type=0x%x, str=%s\n",
- String8(e.name).string(), e.value.dataType,
- String8(e.string).string());
+ String8(e.name).c_str(), e.value.dataType,
+ String8(e.string).c_str());
}
}
}
@@ -1023,30 +1023,30 @@ status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets,
String16 pkg(getNamespaceResourcePackage(String16(assets->getPackage()), e.ns, &nsIsPublic));
if (kIsDebug) {
printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n",
- String8(getElementName()).string(),
- String8(e.name).string(),
- String8(e.string).string(),
- String8(e.ns).string(),
+ String8(getElementName()).c_str(),
+ String8(e.name).c_str(),
+ String8(e.string).c_str(),
+ String8(e.ns).c_str(),
(nsIsPublic) ? "public" : "private",
- String8(pkg).string());
+ String8(pkg).c_str());
}
if (pkg.size() <= 0) continue;
uint32_t res = table != NULL
? table->getResId(e.name, &attr, &pkg, &errorMsg, nsIsPublic)
: assets->getIncludedResources().
- identifierForName(e.name.string(), e.name.size(),
- attr.string(), attr.size(),
- pkg.string(), pkg.size());
+ identifierForName(e.name.c_str(), e.name.size(),
+ attr.c_str(), attr.size(),
+ pkg.c_str(), pkg.size());
if (res != 0) {
if (kIsDebug) {
printf("XML attribute name %s: resid=0x%08x\n",
- String8(e.name).string(), res);
+ String8(e.name).c_str(), res);
}
setAttributeResID(i, res);
} else {
SourcePos(mFilename, getStartLineNumber()).error(
"No resource identifier found for attribute '%s' in package '%s'\n",
- String8(e.name).string(), String8(pkg).string());
+ String8(e.name).c_str(), String8(pkg).c_str());
hasErrors = true;
}
}
@@ -1137,7 +1137,7 @@ status_t XMLNode::flatten(const sp<AaptFile>& dest,
if (kPrintStringMetrics) {
fprintf(stderr, "**** total xml size: %zu / %zu%% strings (in %s)\n",
dest->getSize(), (stringPool->getSize()*100)/dest->getSize(),
- dest->getPath().string());
+ dest->getPath().c_str());
}
return NO_ERROR;
@@ -1155,8 +1155,8 @@ void XMLNode::print(int indent)
if (elemNs.size() > 0) {
elemNs.append(":");
}
- printf("%s E: %s%s", prefix.string(),
- elemNs.string(), String8(getElementName()).string());
+ printf("%s E: %s%s", prefix.c_str(),
+ elemNs.c_str(), String8(getElementName()).c_str());
int N = mAttributes.size();
for (i=0; i<N; i++) {
ssize_t idx = mAttributeOrder.valueAt(i);
@@ -1171,21 +1171,21 @@ void XMLNode::print(int indent)
attrNs.append(":");
}
if (attr.nameResId) {
- printf("%s%s(0x%08x)", attrNs.string(),
- String8(attr.name).string(), attr.nameResId);
+ printf("%s%s(0x%08x)", attrNs.c_str(),
+ String8(attr.name).c_str(), attr.nameResId);
} else {
- printf("%s%s", attrNs.string(), String8(attr.name).string());
+ printf("%s%s", attrNs.c_str(), String8(attr.name).c_str());
}
- printf("=%s", String8(attr.string).string());
+ printf("=%s", String8(attr.string).c_str());
}
printf("\n");
} else if (getType() == TYPE_NAMESPACE) {
- printf("%s N: %s=%s\n", prefix.string(),
+ printf("%s N: %s=%s\n", prefix.c_str(),
getNamespacePrefix().size() > 0
- ? String8(getNamespacePrefix()).string() : "<DEF>",
- String8(getNamespaceUri()).string());
+ ? String8(getNamespacePrefix()).c_str() : "<DEF>",
+ String8(getNamespaceUri()).c_str());
} else {
- printf("%s C: \"%s\"\n", prefix.string(), String8(getCData()).string());
+ printf("%s C: \"%s\"\n", prefix.c_str(), String8(getCData()).c_str());
}
int N = mChildren.size();
for (i=0; i<N; i++) {
@@ -1258,7 +1258,7 @@ void XMLCALL
XMLNode::characterData(void *userData, const XML_Char *s, int len)
{
if (kIsDebugParse) {
- printf("CDATA: \"%s\"\n", String8(s, len).string());
+ printf("CDATA: \"%s\"\n", String8(s, len).c_str());
}
ParseState* st = (ParseState*)userData;
sp<XMLNode> node = NULL;
@@ -1423,7 +1423,7 @@ status_t XMLNode::collect_attr_strings(StringPool* outPool,
idx = outPool->add(attr.name);
if (kIsDebug) {
printf("Adding attr %s (resid 0x%08x) to pool: idx=%zd\n",
- String8(attr.name).string(), id, idx);
+ String8(attr.name).c_str(), id, idx);
}
if (id != 0) {
while ((ssize_t)outResIds->size() <= idx) {
@@ -1434,7 +1434,7 @@ status_t XMLNode::collect_attr_strings(StringPool* outPool,
}
attr.namePoolIdx = idx;
if (kIsDebug) {
- printf("String %s offset=0x%08zd\n", String8(attr.name).string(), idx);
+ printf("String %s offset=0x%08zd\n", String8(attr.name).c_str(), idx);
}
}
}
@@ -1488,7 +1488,7 @@ status_t XMLNode::flatten_node(const StringPool& strings, const sp<AaptFile>& de
node.comment.index = htodl(
mComment.size() > 0 ? strings.offsetForString(mComment) : -1);
//if (mComment.size() > 0) {
- // printf("Flattening comment: %s\n", String8(mComment).string());
+ // printf("Flattening comment: %s\n", String8(mComment).c_str());
//}
} else {
node.comment.index = htodl((uint32_t)-1);
diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp
index 4e8dcb1bc6ee..fc2ed98949dd 100644
--- a/tools/aapt/pseudolocalize.cpp
+++ b/tools/aapt/pseudolocalize.cpp
@@ -42,7 +42,7 @@ String16 Pseudolocalizer::text(const String16& text) {
size_t depth = mLastDepth;
size_t lastpos, pos;
const size_t length= text.size();
- const char16_t* str = text.string();
+ const char16_t* str = text.c_str();
bool escaped = false;
for (lastpos = pos = 0; pos < length; pos++) {
char16_t c = str[pos];
@@ -181,7 +181,7 @@ static bool is_possible_normal_placeholder_end(const char16_t c) {
static String16 pseudo_generate_expansion(const unsigned int length) {
String16 result = k_expansion_string;
- const char16_t* s = result.string();
+ const char16_t* s = result.c_str();
if (result.size() < length) {
result += String16(" ");
result += pseudo_generate_expansion(length - result.size());
@@ -237,7 +237,7 @@ String16 PseudoMethodAccent::end() {
*/
String16 PseudoMethodAccent::text(const String16& source)
{
- const char16_t* s = source.string();
+ const char16_t* s = source.c_str();
String16 result;
const size_t I = source.size();
bool lastspace = true;
@@ -357,7 +357,7 @@ String16 PseudoMethodAccent::placeholder(const String16& source) {
String16 PseudoMethodBidi::text(const String16& source)
{
- const char16_t* s = source.string();
+ const char16_t* s = source.c_str();
String16 result;
bool lastspace = true;
bool space = true;
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index cac4edd8db21..6a17ef85a755 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -457,7 +457,7 @@ void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer*
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
auto str = pool->string8ObjectAt(s);
- printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->string() : ""));
+ printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->c_str() : ""));
}
}
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 1671e1e1a6a1..a92f24b82547 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -215,7 +215,7 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
}
std::vector<std::string> sanitized_config_names;
for (const auto &config : constraints.configs) {
- sanitized_config_names.push_back(MakePackageSafeName(config.toString().string()));
+ sanitized_config_names.push_back(MakePackageSafeName(config.toString().c_str()));
}
split_name << "config." << util::Joiner(sanitized_config_names, "_");
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 75dcba581c90..2e20e8175213 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -453,7 +453,7 @@ bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
const size_t count = entries.size();
for (size_t i = 0; i < count; i++) {
table_->included_packages_[entries.valueAt(i)] =
- android::util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
+ android::util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).c_str()));
}
return true;
}
diff --git a/tools/aapt2/trace/TraceBuffer.cpp b/tools/aapt2/trace/TraceBuffer.cpp
index fab2df383e3f..0988c313b65b 100644
--- a/tools/aapt2/trace/TraceBuffer.cpp
+++ b/tools/aapt2/trace/TraceBuffer.cpp
@@ -44,14 +44,16 @@ struct TracePoint {
std::vector<TracePoint> traces;
bool enabled = true;
+constinit std::chrono::steady_clock::time_point startTime = {};
int64_t GetTime() noexcept {
auto now = std::chrono::steady_clock::now();
- return std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
+ if (startTime == decltype(tracebuffer::startTime){}) {
+ startTime = now;
+ }
+ return std::chrono::duration_cast<std::chrono::microseconds>(now - startTime).count();
}
-} // namespace anonymous
-
void AddWithTime(std::string tag, char type, int64_t time) noexcept {
TracePoint t = {type, getpid(), time, std::move(tag)};
traces.emplace_back(std::move(t));
@@ -76,7 +78,7 @@ void Flush(const std::string& basePath) {
// Wrap the trace in a JSON array [] to make Chrome/Perfetto UI handle it.
char delimiter = '[';
- for(const TracePoint& trace : traces) {
+ for (const TracePoint& trace : traces) {
fprintf(f,
"%c{\"ts\" : \"%" PRIu64
"\", \"ph\" : \"%c\", \"tid\" : \"%d\" , \"pid\" : \"%d\", \"name\" : \"%s\" }\n",
@@ -90,6 +92,8 @@ void Flush(const std::string& basePath) {
traces.clear();
}
+} // namespace
+
} // namespace tracebuffer
void BeginTrace(std::string tag) {
@@ -166,7 +170,7 @@ FlushTrace::FlushTrace(std::string_view basepath, std::string_view tag,
FlushTrace::~FlushTrace() {
if (!tracebuffer::enabled) return;
- tracebuffer::Add(tag_, tracebuffer::kEnd);
+ tracebuffer::Add(std::move(tag_), tracebuffer::kEnd);
tracebuffer::Flush(basepath_);
}
diff --git a/tools/split-select/Grouper_test.cpp b/tools/split-select/Grouper_test.cpp
index 7294a86fa862..a8b78cd3cf7c 100644
--- a/tools/split-select/Grouper_test.cpp
+++ b/tools/split-select/Grouper_test.cpp
@@ -179,7 +179,7 @@ void GrouperTest::expectHasGroupWithSplits(const Vector<const char*>& expectedSt
errorMessage.append("\n");
}
}
- ADD_FAILURE() << errorMessage.string();
+ ADD_FAILURE() << errorMessage.c_str();
}
void GrouperTest::addSplit(Vector<SplitDescription>& splits, const char* str) {
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
index e6966db0aa00..1e751171b370 100644
--- a/tools/split-select/Main.cpp
+++ b/tools/split-select/Main.cpp
@@ -99,8 +99,7 @@ void generate(const KeyedVector<String8, Vector<SplitDescription> >& splits, con
}
masterRule = Rule::simplify(masterRule);
fprintf(stdout, " {\n \"path\": \"%s\",\n \"rules\": %s\n }",
- splits.keyAt(i).string(),
- masterRule->toJson(2).string());
+ splits.keyAt(i).c_str(), masterRule->toJson(2).c_str());
}
fprintf(stdout, "\n]\n");
}
@@ -158,25 +157,23 @@ static bool getAppInfo(const String8& path, AppInfo& outInfo) {
const char16_t* name = xml.getElementName(&len);
String16 name16(name, len);
if (name16 == kManifestTag) {
- ssize_t idx = xml.indexOfAttribute(
- kAndroidNamespace.string(), kAndroidNamespace.size(),
- kVersionCodeAttr.string(), kVersionCodeAttr.size());
+ ssize_t idx = xml.indexOfAttribute(kAndroidNamespace.c_str(), kAndroidNamespace.size(),
+ kVersionCodeAttr.c_str(), kVersionCodeAttr.size());
if (idx >= 0) {
outInfo.versionCode = xml.getAttributeData(idx);
}
} else if (name16 == kApplicationTag) {
- ssize_t idx = xml.indexOfAttribute(
- kAndroidNamespace.string(), kAndroidNamespace.size(),
- kMultiArchAttr.string(), kMultiArchAttr.size());
+ ssize_t idx = xml.indexOfAttribute(kAndroidNamespace.c_str(), kAndroidNamespace.size(),
+ kMultiArchAttr.c_str(), kMultiArchAttr.size());
if (idx >= 0) {
outInfo.multiArch = xml.getAttributeData(idx) != 0;
}
} else if (name16 == kUsesSdkTag) {
- ssize_t idx = xml.indexOfAttribute(
- kAndroidNamespace.string(), kAndroidNamespace.size(),
- kMinSdkVersionAttr.string(), kMinSdkVersionAttr.size());
+ ssize_t idx =
+ xml.indexOfAttribute(kAndroidNamespace.c_str(), kAndroidNamespace.size(),
+ kMinSdkVersionAttr.c_str(), kMinSdkVersionAttr.size());
if (idx >= 0) {
uint16_t type = xml.getAttributeDataType(idx);
if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) {
@@ -187,10 +184,10 @@ static bool getAppInfo(const String8& path, AppInfo& outInfo) {
fprintf(stderr, "warning: failed to retrieve android:minSdkVersion.\n");
} else {
char *endPtr;
- int minSdk = strtol(minSdk8->string(), &endPtr, 10);
- if (endPtr != minSdk8->string() + minSdk8->size()) {
+ int minSdk = strtol(minSdk8->c_str(), &endPtr, 10);
+ if (endPtr != minSdk8->c_str() + minSdk8->size()) {
fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n",
- minSdk8->string());
+ minSdk8->c_str());
} else {
outInfo.minSdkVersion = minSdk;
}
@@ -232,7 +229,7 @@ static Vector<SplitDescription> extractSplitDescriptionsFromApk(const String8& p
splits.add();
Vector<String8> parts = AaptUtil::splitAndLowerCase(dir->getFileName(i), '-');
if (parseAbi(parts, 0, &splits.editTop()) < 0) {
- fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).string());
+ fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).c_str());
splits.pop();
}
}
@@ -291,7 +288,7 @@ static int main(int argc, char** argv) {
help();
return 0;
} else {
- fprintf(stderr, "error: unknown argument '%s'.\n", arg.string());
+ fprintf(stderr, "error: unknown argument '%s'.\n", arg.c_str());
usage();
return 1;
}
@@ -313,15 +310,14 @@ static int main(int argc, char** argv) {
// Find out some details about the base APK.
AppInfo baseAppInfo;
if (!getAppInfo(baseApkPath, baseAppInfo)) {
- fprintf(stderr, "error: unable to read base APK: '%s'.\n", baseApkPath.string());
+ fprintf(stderr, "error: unable to read base APK: '%s'.\n", baseApkPath.c_str());
return 1;
}
SplitDescription targetSplit;
if (!generateFlag) {
if (!SplitDescription::parse(targetConfigStr, &targetSplit)) {
- fprintf(stderr, "error: invalid --target config: '%s'.\n",
- targetConfigStr.string());
+ fprintf(stderr, "error: invalid --target config: '%s'.\n", targetConfigStr.c_str());
usage();
return 1;
}
@@ -341,7 +337,7 @@ static int main(int argc, char** argv) {
Vector<SplitDescription> splits = extractSplitDescriptionsFromApk(splitApkPaths[i]);
if (splits.isEmpty()) {
fprintf(stderr, "error: invalid --split path: '%s'. No splits found.\n",
- splitApkPaths[i].string());
+ splitApkPaths[i].c_str());
usage();
return 1;
}
@@ -364,7 +360,7 @@ static int main(int argc, char** argv) {
const size_t matchingSplitApkPathCount = matchingSplitPaths.size();
for (size_t i = 0; i < matchingSplitApkPathCount; i++) {
if (matchingSplitPaths[i] != baseApkPath) {
- fprintf(stdout, "%s\n", matchingSplitPaths[i].string());
+ fprintf(stdout, "%s\n", matchingSplitPaths[i].c_str());
}
}
} else {
diff --git a/tools/split-select/Rule_test.cpp b/tools/split-select/Rule_test.cpp
index c6cff0d0220e..c78533fd1907 100644
--- a/tools/split-select/Rule_test.cpp
+++ b/tools/split-select/Rule_test.cpp
@@ -68,7 +68,7 @@ TEST(RuleTest, generatesValidJson) {
expected.erase(std::remove_if(expected.begin(), expected.end(), ::isspace), expected.end());
// Result
- std::string result(rule.toJson().string());
+ std::string result(rule.toJson().c_str());
result.erase(std::remove_if(result.begin(), result.end(), ::isspace), result.end());
ASSERT_EQ(expected, result);
diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp
index 99bc23d819fb..4e2b48e1f450 100644
--- a/tools/split-select/SplitDescription.cpp
+++ b/tools/split-select/SplitDescription.cpp
@@ -134,8 +134,8 @@ bool SplitDescription::parse(const String8& str, SplitDescription* outSplit) {
String8 configStr;
String8 extensionStr;
if (index >= 0) {
- configStr.setTo(str.string(), index);
- extensionStr.setTo(str.string() + index + 1);
+ configStr.setTo(str.c_str(), index);
+ extensionStr.setTo(str.c_str() + index + 1);
} else {
configStr.setTo(str);
}
diff --git a/tools/split-select/TestRules.cpp b/tools/split-select/TestRules.cpp
index 86ccd6a25c18..ca3c56fe861c 100644
--- a/tools/split-select/TestRules.cpp
+++ b/tools/split-select/TestRules.cpp
@@ -78,9 +78,8 @@ const Rule AlwaysTrue() {
const String8 actualStr(actual != NULL ? actual->toJson() : String8());
if (expectedStr != actualStr) {
- return ::testing::AssertionFailure()
- << "Expected: " << expectedStr.string() << "\n"
- << " Actual: " << actualStr.string();
+ return ::testing::AssertionFailure() << "Expected: " << expectedStr.c_str() << "\n"
+ << " Actual: " << actualStr.c_str();
}
return ::testing::AssertionSuccess();
}